Layout

For the first time in our GoMail examples, we have a toolkit that provides all of the layouts required to match the user interface we designed at the beginning of Section 2, Toolkits Using Existing Widgets. That's perhaps no surprise, as it was created using the Qt tools, but it's a chance to explore the more complete set of layouts provided by Qt and made available using the qt bindings. The most useful ones are the following:

Layout Description
box The box layout is very familiar by now; it lays out widgets in a horizontal or vertical box. Therefore, it's created with widgets.NewQVBoxLayout() or widgets.NewQVBoxLayout() accordingly.
form

This is a convenience layout that's basically a two-column grid where all of the widgets in the left column are labels. This is styled accordingly to produce the design we saw in Qt Creator.

grid

This layout represents a flexible grid layout so that cells aren't forced to all be the same size but instead rows and columns flex to accommodate the minimum size of items packed into the grid.

spacer

While not strictly a layout, the spacer item can be used in layouts to create visual space. Constructed using widgets.NewQSpacerItem(width, height, hPolicy, vPolicy), it's possible to add various different types of space using this helpful class.

stacked

A stacked layout sets all child objects to be the full size of the containing widget, but ensures that only one can be visible at a time. The SetCurrentWidget() and SetCurrentIndex() functions can be used to control which child is visible. This is very useful for implementing tabbed panels or paged controls.

Using this knowledge, we can re-create the GoMail browse interface using pure Qt widgets. A lot of this code will be familiar by now, but there are a number of notable differences. Firstly, you can see that layouts (as listed previously) are typically set on widgets.QWidget rather than creating a whole new widget for their own purpose. This approach means that the number of different widgets can be kept lower, but it also causes some functionality to be attached to the layout and not the widget. For example, the widgets.NewQFormLayout() we set on the detail widget is designed to lay out form components, and as such has helper functions to add rows (form.AddRow3, for example). To use these functions, we must keep a reference to the layout (the form variable in this code) to operate on. You can also see that AddWidget() is called on widget.Layout() rather than on widget directly.

This snippet contains most of the code to create our basic layout. Some of the toolbar and menu code (which is rather repetitive) has been left out, but it can be found in the code repository that accompanies this book. We start with the imports and a basic skeleton for creating a menu bar:

package main

import (
"github.com/therecipe/qt/core"
"github.com/therecipe/qt/gui"
"github.com/therecipe/qt/widgets"
"os"
)

func buildMenu() *widgets.QMenuBar {
menu := widgets.NewQMenuBar(nil)

file := widgets.NewQMenu2("File", menu)
...
menu.AddMenu(file)

...

return menu
}

And similarly, we can create a new toolbar using built-in icons:

func buildToolbar() *widgets.QToolBar {
toolbar := widgets.NewQToolBar("tools", nil)
toolbar.SetToolButtonStyle(core.Qt__ToolButtonTextUnderIcon)
toolbar.AddAction2(gui.QIcon_FromTheme2("document-new", nil), "New")

...

return toolbar
}

And lastly, we lay out the main content of the window:

func main() {
widgets.NewQApplication(len(os.Args), os.Args)

window := widgets.NewQMainWindow(nil, 0)
window.SetWindowTitle("GoMail")

widget := widgets.NewQWidget(window, 0)
widget.SetLayout(widgets.NewQVBoxLayout())
window.SetMinimumSize2(600, 400)
window.SetCentralWidget(widget)

window.SetMenuBar(buildMenu())
widget.Layout().AddWidget(buildToolbar())

list := widgets.NewQTreeView(window)
list.SetModel(core.NewQStringListModel2([]string{"email1", "email2"}, widget))

detail := widgets.NewQWidget(window, 0)
form := widgets.NewQFormLayout(detail)
detail.SetLayout(form)
form.AddRow5(widgets.NewQLabel2("subject", detail, 0))
form.AddRow3("From", widgets.NewQLabel2("email", detail, 0))
form.AddRow3("To", widgets.NewQLabel2("email", detail, 0))
form.AddRow3("Date", widgets.NewQLabel2("date", detail, 0))
form.AddRow5(widgets.NewQLabel2("content", detail, 0))

splitter := widgets.NewQSplitter(window)
splitter.AddWidget(list)
splitter.AddWidget(detail)
widget.Layout().AddWidget(splitter)

window.Show()
widgets.QApplication_Exec()
}

The preceding code is similar in structure to the previous chapter (as GTK+ and Qt APIs have many similarities), though the naming will remind you of Chapter 4Walk - Building Graphical Windows Applications, and the Walk example. Clearly, as Walk is based largely on Qt, the naming is often the same, but the qt APIs being used here don't offer the same declarative syntax and so must be created using the function-based constructors.

This example introduces two new qt packages, core and gui. As you can see from the example, we use the core package with data models (which many of the more complex widgets make use of). The gui package provides helpful additions to make a user interface more compelling; in this instance, we're looking up standard icons using the gui.QIcon_FromTheme2 function. In a more complete application, we could provide fallback icons that would complete the Reply and Reply All toolbar buttons:

The complete layout of our GoMail application using qt

As you can see from this screenshot, a qt application can look polished with even the most basic of code. You may notice the 1 above our email list instead of Inbox; this is due to a limitation in core.QStringListModel used for this layout example and should be addressed in our full implementation.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.26.138