Qt参考文档

初步了解 | 进一步了解 | 最新动态
  • 关于Qt
  • Qt的版本
  • 常见问题解答
  • Window系统特性注释
  • 如何购买Qt
  • 安装
  • 如何学习Qt
  • 教程一， 教程二
  • 实例
  • 循序渐进实例
  • 白皮书
  • Qt 3.0的关键特征
  • 修改历史
  • 从Qt 2.x移植到Qt 3.x
  • 简体中文汉化日志
  • Qt季刊
API参考 | 模块 | 概述
  • 所有的类
  • 主要的类
  • 分组的类
  • 注释的类
  • 继承关系
  • 类表(图像)
  • 所有的函数(很长)
  • 头文件索引

  • PDF格式文档
  • man帮助格式文档
  • 关于模块
  • 画布
  • 图标视图
  • 网络
  • OpenGL
  • SQL
  • 表格
  • 工作区
  • XML
  • 概述与HOWTO
  • Qt对象模型
  • 信号与槽
  • 窗口几何结构
  • 事件和事件过滤器
  • 国际化(i18n)
  • 调试技术
  • Qt中的线程支持
  • Qt插件
  • 窗口部件快照

Trolltech | 工具 | 附录
  • 关于Trolltech公司
  • 如何报告bug
  • 邮件列表信息
  • 所有的工具
  • Qt设计器
  • Qt语言学家
  • Qt助手
  • qmake
  • 标准快捷键
  • Q公共许可证
  • GNU通用公共许可证
  • Qt中使用的其它许可证
  • 鸣谢

Copyright © 2002 Trolltech Trademarks 译者:Cavendish
Qt 3.0.5版


关于Qt

Qt是一个多平台的C++图形用户界面应用程序框架。它提供给应用程序开发者建立 艺术级的图形用户界面所需的所用功能。Qt是完全面向对象的很容易扩展，并且 允许真正地组件编程。

自从1996年早些时候，Qt进入商业领域，它已经成为全世界范围内数千种成功的应用 程序的基础。Qt也是流行的Linux桌面环境KDE 的基础，KDE是所有主要的Linux发行版的一个标准组件。

Qt支持下述平台：

  • MS/Windows - 95、98、NT 4.0、ME、和2000
  • Unix/X11 - Linux、Sun Solaris、HP-UX、Compaq Tru64 UNIX、IBM AIX、SGI IRIX和其它很多X11平台
  • Macintosh - Mac OS X
  • Embedded - 有帧缓冲(framebuffer)支持的Linux平台。

Qt是Trolltech公司的一个产品。

Qt被按不同的版本发行：

Qt企业版和Qt专业版 提供给商业软件开发。它们提供传统商业软件发行版并且提供免费升级和技术支持服务。 如果要获得最新报价，请浏览Trolltech公司网站的价格和可行性页面，或者与sales@trolltech.com联系。 企业版比专业版多一些扩展模块。

Qt自由版是Qt仅仅为了开发自由和开放源码软件 提供的Unix/X11版本。在Q公共许可证和GNU通用公共许可证 下，它是免费的。最新的版本可以在这里下载。

Qt/嵌入式自由版是Qt为了开发自由软件提供的嵌入式版本。 在GNU通用公共许可证下，它是免费的。

Copyright © 2002 Trolltech Trademarks 译者:Cavendish
Qt 3.0.5版


FAQs

This document describes how to use more than one Qt version on one machine and how to use Qt on X11 without a window manager. In addition it explains the most common source of link errors with Qt.
这个文档描述了如何在一台机器上使用超过一个版本的Qt和如何在X11中使用没有窗口管理器的Qt。 另外，还有使用Qt时的一些最常见的Source链接错误。

Other frequently asked questions can be found in the
其他的常见问题(FAQs)能够在 FAQ index 和 Technical FAQ中发现.

  • Link error, complaining about a lack of \c vtbl, \c _vtbl, \c __vtbl or similar
  • 链接错误，\c vtbl, \c _vtbl, \c __vtbl或者相似问题缺乏的报告。
  • Using different versions of Qt on the same machine
  • 在同一台计算机上使用不同版本的Qt
    • Developers building for a single version of Qt on Unix - Qt binary packages
    • 在Unix上，开发人员为单一的Qt版本构建环境(Building) - Qt二进制包(binary packages)
    • Developers building for two versions of Qt on Unix - Qt sources
    • 在Unix上，开发人员为两个Qt版本构建环境(Building) - Qt源代码(sources)
  • Using Qt on X11 without a window manager
  • 在X11中使用没有窗口管理器的Qt

Link error, complaining about a lack of vtbl, _vtbl, __vtbl or similar

链接错误, vtbl, _vtbl, __vtbl或者相似问题缺乏的报告

This indicates that you've included the Q_OBJECT macro in a class declaration and probably also run the moc, but forgot to link the moc-generated object code into your executable. See Using the Meta Object Compiler for details on how to use moc.

Using different versions of Qt on the same machine

Qt programs need the following components of a Qt distribution:

Header files - Compile time

Programmers need to include the Qt header files. The Qt header files are usually located in the include subdirectory of Qt distributions. Care must be taken to include the header files of the relevant release of Qt. Those with a command-line compiler will typically use options such as /I%QTDIR%\include the relevant release of Qt.

Meta Object Compiler and other tools - Compile time

Programmers need to run moc and other tools such as uic. These tools are usually located in the bin subdirectory of Qt distributions. Either run "$QTDIR"/bin/moc and "$QTDIR"/bin/uic or add "$QTDIR"/bin to your PATH and run moc and uic. If you use qmake the appropriate lines will be added to your Makefiles so that uic and moc will be executed as required.

Static or shared libraries - Link time

Programmers need to link with the Qt static or shared libraries. The Qt libraries are usually located in the lib subdirectory of Qt distributions. Care must be taken to link with the libraries of the relevant release of Qt. Those with a command-line compiler will typically use options such as /L%QTDIR%\lib\qt.lib or -L"$QTDIR"/lib -lqt provided QTDIR specifies the relevant release of Qt.

Shared libraries - Run time

Users of programs linked with shared Qt libraries need these same shared libraries to run these programs. The Qt libraries are usually located in the lib subdirectory of Qt distributions. Shared libraries are made available to programs in places such as C:\windows\system on Windows platforms, directories listed in file /etc/ld.so.conf on Linux, standard lib directories on Unix, or directories listed in environment variables LD_LIBRARY_PATH, SHLIB_PATH, or LIBPATH on various Unix flavours. Make the relevant Qt libraries available using one of these mechanisms.

Qt distributions consist of different files needed at compile time, link time, or run time. Trolltech distributes Qt in the form of a source package that contain all these files once they have been built.

Other vendors distribute Qt in the form of binary packages. Binary packages usually consist of two parts:

  • shared libraries in the run time package, usually called qt3.

  • header files, static libraries, the moc and other tools in the developers' kit, usually called qt3-dev.

Depending on how you are using Qt, you need to make specific parts of the Qt distribution available to your programs. Typical situations are described below.

Developers building for a single version of Qt on Unix - Qt binary packages

You build programs with a single version of Qt, but you still need to run programs linked with another version of Qt. You are typically a Linux developer who builds programs for Qt 3.x on a KDE desktop based on Qt 2.x. Qt packages are usually split into a shared library package with a name like qt and a developer package with a name like qt-dev. You will need the appropriate packages:

  • To build programs you will need the header files, the libraries, the moc and other tools from Qt 3.x. They are included in the developer package of Qt 3.x (qt3-dev or similar).

  • To run programs you will need the shared libraries of Qt 3.x and Qt 2.x. They are included in the regular packages of Qt 3.x (qt3 or similar) and Qt 2.x (qt2 or similar).

Just install the packages, qt2, qt3, and qt3-dev. You may need to set the environment variable QTDIR to point to Qt 3.x.

Developers building for two versions of Qt on Unix - Qt sources

You build and run programs for Qt 2.x and Qt 3.x. You will need:

  • the header files, the libraries, the moc and other tools from Qt 3.x and Qt 2.x to build programs,

  • the shared libraries of Qt 3.x and Qt 2.x to run programs.

Get the source distributions of both Qt 2.x and Qt 3.x.

  1. Install and build Qt 2.x and Qt 3.x, usually in /opt or /usr/local. In the case of /opt:

    $ cd /opt
$ gunzip -c \c qt-x11-2.3.1.tar.gz | tar xf -
$ cd qt-2.3.1
$ setenv QTDIR /opt/qt-2.3.1
$ configure [options]
$ make

$ cd /opt
$ gunzip -c qt-x11-free-3.0.0.tar.gz | tar xf -
$ cd qt-3.0.0
$ setenv QTDIR /opt/qt-3.0.0
$ configure [options]
$ make

  2. Make shared libraries available to programs at run time. Either add both /opt/qt-2.3.1/lib and /opt/qt-3.0.0/lib to your environment variable LD_LIBRARY_PATH or file /etc/ld.so.conf or whataver mechanism you're using, or make links to the libraries in a standard directory like /usr/local/lib:

    cd /usr/local/lib
ln -s /opt/qt-2.3.1/lib/libqt.so.2 .
ln -s /opt/qt-2.3.1/lib/libqt-mt.so.2 .
ln -s /opt/qt-2.3.1/lib/libqutil.so.1 .
ln -s /opt/qt-3.0.0/lib/libqt.so.3 .
ln -s /opt/qt-3.0.0/lib/libqui.so.1 .

To develop with Qt 2.x use:

setenv QTDIR /opt/qt-2.3.1
setenv PATH ${QTDIR}/bin:${PATH}

To develop with Qt 3.x use:

setenv QTDIR /opt/qt-3.0.0
setenv PATH ${QTDIR}/bin:${PATH}

Setting QTDIR ensures that the proper resources are used, such as the documentation appropriate to the version of Qt you're using. Also your Makfiles may refer to "$QTDIR"/include and "$QTDIR"/lib to include the proper header files and link with the proper libraries. Setting the PATH ensures that the proper version of moc and other tools is being used.

Using Qt on X11 without a window manager

When using Qt without a window manager on Unix/X11, you will most likely experience focus problems. Without a window manager, there is no focus handling on X11, and no concept of an active window either. If you want your application to work in such an environment, you have to explicitly mark a window as active after showing it:

 yourWindow->show();
 yourWindow->setActiveWindow();

Note that setActiveWindow() won't work if the widget does not become physically visible during this event cycle. However, without a window manager running, this is guaranteed to happen. For the curious reader: setActiveWindow() emulates a window manager by explicitly setting the X Input Focus to a widget's top level window.

Copyright © 2002 TrolltechTrademarks
Qt version 3.0.5


如何购买Qt

你可以通过把定购表单打印出来并传真到+47 21 60 48 01来定购Qt企业版和Qt专业版。对于价格，请查看定价和实用性页面。

我们接受如下支付方式：

  • 信用卡（VISA、American Express、Mastercard、JCB）
  • 支票（美国的或者国际的）
  • SWIFT 国际银行转帐（细节请看定购表单）

（因为被信用卡公司的强加限制，我们不能通过网页或者e-mail方式接受信用卡订单，我们必须收到签字的订单表格。）

支票和定购表单也可以使用平信方式邮寄到：

Trolltech AS
Waldemar Thranes gate 98
N-0175 Oslo
NORWAY

有关定购和价格的问题，请通过sales@trolltech.com或者电话+47 21 60 48 00联系我们。

Copyright © 2002 Trolltech Trademarks 译者:Cavendish
Qt 3.0.5版


Qt的类

如果想看一个更紧凑的列表，请参考Qt的主要类.

A | QAccel |  | QDockWindow |  | QImageFormatPlugin |  | QProgressDialog |  | QTableSelection
 | QAccessible |  | QDomAttr |  | QImageFormatType |  | QPtrCollection |  | QTabletEvent
 | QAccessibleInterface |  | QDomCDATASection |  | QImageIO |  | QPtrDict |  | QTabWidget
 | QAccessibleObject |  | QDomCharacterData |  | QIMEvent |  | QPtrDictIterator |  | QTextBrowser
 | QAction |  | QDomComment |  | QInputDialog |  | QPtrList |  | QTextCodec
 | QActionGroup |  | QDomDocument |  | QIntCache |  | QPtrListIterator |  | QTextCodecPlugin
 | QApplication |  | QDomDocumentFragment |  | QIntCacheIterator |  | QPtrQueue |  | QTextDecoder
 | QAsciiCache |  | QDomDocumentType |  | QIntDict |  | QPtrStack |  | QTextDrag
 | QAsciiCacheIterator |  | QDomElement |  | QIntDictIterator |  | QPtrVector |  | QTextEdit
 | QAsciiDict |  | QDomEntity |  | QIntValidator |  | QPushButton |  | QTextEncoder
 | QAsciiDictIterator |  | QDomEntityReference |  | QIODevice | R | QRadioButton |  | QTextIStream
B | QBitArray |  | QDomImplementation | J | QJisCodec |  | QRangeControl |  | QTextOStream
 | QBitmap |  | QDomNamedNodeMap | K | QKeyEvent |  | QRect |  | QTextStream
 | QBitVal |  | QDomNode |  | QKeySequence |  | QRegExp |  | QThread
 | QBoxLayout |  | QDomNodeList | L | QLabel |  | QRegExpValidator |  | QTime
 | QBrush |  | QDomNotation |  | QLayout |  | QRegion |  | QTimeEdit
 | QBuffer |  | QDomProcessingInstruction |  | QLayoutItem |  | QResizeEvent |  | QTimer
 | QButton |  | QDomText |  | QLayoutIterator | S | QScreen |  | QTimerEvent
 | QButtonGroup |  | QDoubleValidator |  | QLCDNumber |  | QScrollBar |  | QToolBar
 | QByteArray |  | QDragEnterEvent |  | QLibrary |  | QScrollView |  | QToolButton
C | QCache |  | QDragLeaveEvent |  | QLineEdit |  | QSemaphore |  | QToolTip
 | QCacheIterator |  | QDragMoveEvent |  | QListBox |  | QServerSocket |  | QToolTipGroup
 | QCanvas |  | QDragObject |  | QListBoxItem |  | QSessionManager |  | QTranslator
 | QCanvasEllipse |  | QDropEvent |  | QListBoxPixmap |  | QSettings |  | QTranslatorMessage
 | QCanvasItem | E | QEditorFactory |  | QListBoxText |  | QSGIStyle |  | QTsciiCodec
 | QCanvasItemList |  | QErrorMessage |  | QListView |  | QShowEvent | U | QUriDrag
 | QCanvasLine |  | QEucJpCodec |  | QListViewItem |  | QSignal |  | QUrl
 | QCanvasPixmap |  | QEucKrCodec |  | QListViewItemIterator |  | QSignalMapper |  | QUrlInfo
 | QCanvasPixmapArray |  | QEvent |  | QLocalFs |  | QSimpleRichText |  | QUrlOperator
 | QCanvasPolygon | F | QFile |  | QLock |  | QSize | V | QValidator
 | QCanvasPolygonalItem |  | QFileDialog | M | QMainWindow |  | QSizeGrip |  | QValueList
 | QCanvasRectangle |  | QFileIconProvider |  | QMap |  | QSizePolicy |  | QValueListConstIterator
 | QCanvasSpline |  | QFileInfo |  | QMapConstIterator |  | QSjisCodec |  | QValueListIterator
 | QCanvasSprite |  | QFilePreview |  | QMapIterator |  | QSlider |  | QValueStack
 | QCanvasText |  | QFocusData |  | QMemArray |  | QSocket |  | QValueVector
 | QCanvasView |  | QFocusEvent |  | QMenuBar |  | QSocketDevice |  | QVariant
 | QCDEStyle |  | QFont |  | QMenuData |  | QSocketNotifier |  | QVBox
 | QChar |  | QFontDatabase |  | QMessageBox |  | QSound |  | QVBoxLayout
 | QCharRef |  | QFontDialog |  | QMetaObject |  | QSpacerItem |  | QVButtonGroup
 | QCheckBox |  | QFontInfo |  | QMetaProperty |  | QSpinBox |  | QVGroupBox
 | QCheckListItem |  | QFontManager |  | QMimeSource |  | QSplitter | W | QWaitCondition
 | QCheckTableItem |  | QFontMetrics |  | QMimeSourceFactory |  | QSql |  | QWhatsThis
 | QChildEvent |  | QFrame |  | QMotifPlusStyle |  | QSqlCursor |  | QWheelEvent
 | QClipboard |  | QFtp |  | QMotifStyle |  | QSqlDatabase |  | QWidget
 | QCloseEvent | G | QGb18030Codec |  | QMouseEvent |  | QSqlDriver |  | QWidgetFactory
 | QColor |  | QGbkCodec |  | QMoveEvent |  | QSqlDriverPlugin |  | QWidgetItem
 | QColorDialog |  | QGL |  | QMovie |  | QSqlEditorFactory |  | QWidgetPlugin
 | QColorDrag |  | QGLayoutIterator |  | QMutex |  | QSqlError |  | QWidgetStack
 | QColorGroup |  | QGLColormap | N | QNetworkOperation |  | QSqlField |  | QWindowsMime
 | QComboBox |  | QGLContext |  | QNetworkProtocol |  | QSqlFieldInfo |  | QWindowsStyle
 | QComboTableItem |  | QGLFormat |  | QNPInstance * |  | QSqlForm |  | QWizard
 | QCommonStyle |  | QGLWidget |  | QNPlugin * |  | QSqlIndex |  | QWMatrix
 | QConstString |  | QGrid |  | QNPStream * |  | QSqlPropertyMap |  | QWorkspace
 | QContextMenuEvent |  | QGridLayout |  | QNPWidget * |  | QSqlQuery |  | QWSDecoration
 | QCopChannel |  | QGridView | O | QObject |  | QSqlRecord |  | QWSKeyboardHandler
 | QCString |  | QGroupBox |  | QObjectCleanupHandler |  | QSqlRecordInfo |  | QWSMouseHandler
 | QCursor |  | QGuardedPtr |  | QObjectList |  | QSqlResult |  | QWSServer
 | QCustomEvent | H | QHBox |  | QObjectListIt |  | QStatusBar |  | QWSWindow
 | QCustomMenuItem |  | QHBoxLayout | P | QPaintDevice |  | QStoredDrag | X | QXmlAttributes
D | QDataBrowser |  | QHButtonGroup |  | QPaintDeviceMetrics |  | QStrIList |  | QXmlContentHandler
 | QDataStream |  | QHeader |  | QPainter |  | QString |  | QXmlDeclHandler
 | QDataTable |  | QHebrewCodec |  | QPaintEvent |  | QStringList |  | QXmlDefaultHandler
 | QDataView |  | QHGroupBox |  | QPair |  | QStrList |  | QXmlDTDHandler
 | QDate |  | QHideEvent |  | QPalette |  | QStrListIterator |  | QXmlEntityResolver
 | QDateEdit |  | QHostAddress |  | QPen |  | QStyle |  | QXmlErrorHandler
 | QDateTime |  | QHttp |  | QPicture |  | QStyleFactory |  | QXmlInputSource
 | QDateTimeEdit | I | QIconDrag |  | QPixmap |  | QStyleOption |  | QXmlLexicalHandler
 | QDesktopWidget |  | QIconDragItem |  | QPixmapCache |  | QStylePlugin |  | QXmlLocator
 | QDial |  | QIconSet |  | QPlatinumStyle |  | QStyleSheet |  | QXmlNamespaceSupport
 | QDialog |  | QIconView |  | QPNGImagePacker |  | QStyleSheetItem |  | QXmlParseException
 | QDict |  | QIconViewItem |  | QPoint | T | Qt |  | QXmlReader
 | QDictIterator |  | QImage |  | QPointArray |  | QTab |  | QXmlSimpleReader
 | QDir |  | QImageConsumer |  | QPopupMenu |  | QTabBar |  | QXtApplication *
 | QDirectPainter |  | QImageDecoder |  | QPrinter |  | QTabDialog |  | QXtWidget *
 | QDns |  | QImageDrag |  | QProcess |  | QTable |  |
 | QDockArea |  | QImageFormat |  | QProgressBar |  | QTableItem |  |

* NSPlugin和Xt/Motif的扩展类。

Copyright © 2002 Trolltech Trademarks 译者:Cavendish
Qt 3.0.5版


Annotated Class Index

Here are the classes in Qt, with brief descriptions:

QAccel | Handles keyboard accelerator and shortcut keys
QAccessible | Enums and static functions relating to accessibility
QAccessibleInterface | Defines an interface that exposes information about accessible objects
QAccessibleObject | Implements parts of the QAccessibleInterface for QObjects
QAction | Abstract user interface action that can appear both in menus and tool bars
QActionGroup | Groups actions together
QApplication | Manages the GUI application's control flow and main settings
QAsciiCache | Template class that provides a cache based on char* keys
QAsciiCacheIterator | Iterator for QAsciiCache collections
QAsciiDict | Template class that provides a dictionary based on char* keys
QAsciiDictIterator | Iterator for QAsciiDict collections
QBitArray | Array of bits
QBitVal | Internal class, used with QBitArray
QBitmap | Monochrome (1-bit depth) pixmaps
QBoxLayout | Lines up child widgets horizontally or vertically
QBrush | Defines the fill pattern of shapes drawn by a QPainter
QBuffer | I/O device that operates on a QByteArray
QButton | The abstract base class of button widgets, providing functionality common to buttons
QButtonGroup | Organizes QButton widgets in a group
QByteArray | Array of bytes
QCDEStyle | CDE look and feel
QCString | Abstraction of the classic C zero-terminated char array (char *)
QCache | Template class that provides a cache based on QString keys
QCacheIterator | Iterator for QCache collections
QCanvas | 2D area that can contain QCanvasItem objects
QCanvasEllipse | Ellipse or ellipse segment on a QCanvas
QCanvasItem | Abstract graphic object on a QCanvas
QCanvasItemList | List of QCanvasItems
QCanvasLine | Line on a QCanvas
QCanvasPixmap | Pixmaps for QCanvasSprites
QCanvasPixmapArray | Array of QCanvasPixmaps
QCanvasPolygon | Polygon on a QCanvas
QCanvasPolygonalItem | Polygonal canvas item on a QCanvas
QCanvasRectangle | Rectangle on a QCanvas
QCanvasSpline | Multi-bezier splines on a QCanvas
QCanvasSprite | Animated canvas item on a QCanvas
QCanvasText | Text object on a QCanvas
QCanvasView | On-screen view of a QCanvas
QChar | Lightweight Unicode character
QCharRef | Helper class for QString
QCheckBox | Checkbox with a text label
QCheckListItem | Checkable list view items
QCheckTableItem | Checkboxes in QTables
QChildEvent | Event parameters for child object events
QClipboard | Access to the window system clipboard
QCloseEvent | Parameters that describe a close event
QColor | Colors based on RGB or HSV values
QColorDialog | Dialog widget for specifying colors
QColorDrag | Drag and drop object for transferring colors
QColorGroup | Group of widget colors
QComboBox | Combined button and popup list
QComboTableItem | Means of using comboboxes in QTables
QCommonStyle | Encapsulates the common Look and Feel of a GUI
QConstString | String objects using constant Unicode data
QContextMenuEvent | Parameters that describe a context menu event
QCopChannel | Communication capabilities between several clients
QCursor | Mouse cursor with an arbitrary shape
QCustomEvent | Support for custom events
QCustomMenuItem | Abstract base class for custom menu items in popup menus
QDataBrowser | Data manipulation and navigation for data entry forms
QDataStream | Serialization of binary data to a QIODevice
QDataTable | Flexible SQL table widget that supports browsing and editing
QDataView | Read-only SQL forms
QDate | Date functions
QDateEdit | Date editor
QDateTime | Date and time functions
QDateTimeEdit | Combines a QDateEdit and QTimeEdit widget into a single widget for editing datetimes
QDesktopWidget | Access to screen information on multi-head systems
QDial | Rounded range control (like a speedometer or potentiometer)
QDialog | The base class of dialog windows
QDict | Template class that provides a dictionary based on QString keys
QDictIterator | Iterator for QDict collections
QDir | Access to directory structures and their contents in a platform-independent way
QDirectPainter | Direct access to the video hardware
QDns | Asynchronous DNS lookups
QDockArea | Manages and lays out QDockWindows
QDockWindow | Widget which can be docked inside a QDockArea or floated as a top level window on the desktop
QDomAttr | Represents one attribute of a QDomElement
QDomCDATASection | Represents an XML CDATA section
QDomCharacterData | Represents a generic string in the DOM
QDomComment | Represents an XML comment
QDomDocument | Represents an XML document
QDomDocumentFragment | Tree of QDomNodes which is not usually a complete QDomDocument
QDomDocumentType | The representation of the DTD in the document tree
QDomElement | Represents one element in the DOM tree
QDomEntity | Represents an XML entity
QDomEntityReference | Represents an XML entity reference
QDomImplementation | Information about the features of the DOM implementation
QDomNamedNodeMap | Collection of nodes that can be accessed by name
QDomNode | The base class for all the nodes in a DOM tree
QDomNodeList | List of QDomNode objects
QDomNotation | Represents an XML notation
QDomProcessingInstruction | Represents an XML processing instruction
QDomText | Represents text data in the parsed XML document
QDoubleValidator | Range checking of floating-point numbers
QDragEnterEvent | Event which is sent to the widget when a drag and drop first drags onto the widget
QDragLeaveEvent | Event which is sent to the widget when a drag and drop leaves the widget
QDragMoveEvent | Event which is sent while a drag and drop is in progress
QDragObject | Encapsulates MIME-based data transfer
QDropEvent | Event which is sent when a drag and drop is completed
QEditorFactory | Used to create editor widgets for QVariant data types
QErrorMessage | Error message display dialog
QEucJpCodec | Conversion to and from EUC-JP character sets
QEucKrCodec | Conversion to and from EUC-KR character sets
QEvent | The base class of all event classes. Event objects contain event parameters
QFile | I/O device that operates on files
QFileDialog | Dialogs that allow users to select files or directories
QFileIconProvider | Icons for QFileDialog to use
QFileInfo | System-independent file information
QFilePreview | File previewing in QFileDialog
QFocusData | Maintains the list of widgets in the focus chain
QFocusEvent | Event parameters for widget focus events
QFont | Font used for drawing text
QFontDatabase | Information about the fonts available in the underlying window system
QFontDialog | Dialog widget for selecting a font
QFontInfo | General information about fonts
QFontManager | Implements font management in Qt/Embedded
QFontMetrics | Font metrics information
QFrame | The base class of widgets that can have a frame
QFtp | Implementation of the FTP protocol
QGL | Namespace for miscellaneous identifiers in the Qt OpenGL module
QGLColormap | Used for installing custom colormaps into QGLWidgets
QGLContext | Encapsulates an OpenGL rendering context
QGLFormat | The display format of an OpenGL rendering context
QGLWidget | Widget for rendering OpenGL graphics
QGLayoutIterator | Abstract base class of internal layout iterators
QGb18030Codec | Conversion to and from the Chinese GB18030/GBK/GB2312 encoding
QGbkCodec | Conversion to and from the Chinese GBK encoding
QGrid | Simple geometry management of its children
QGridLayout | Lays out widgets in a grid
QGridView | Abstract base for fixed-size grids
QGroupBox | Group box frame with a title
QGuardedPtr | Template class that provides guarded pointers to QObjects
QHBox | Horizontal geometry management for its child widgets
QHBoxLayout | Lines up widgets horizontally
QHButtonGroup | Organizes QButton widgets in a group with one horizontal row
QHGroupBox | Organizes widgets in a group with one horizontal row
QHeader | Header row or column, e.g. for tables and listviews
QHebrewCodec | Conversion to and from visually ordered Hebrew
QHideEvent | Event which is sent after a widget is hidden
QHostAddress | IP address
QHttp | Implementation of the HTTP protocol
QIMEvent | Parameters for input method events
QIODevice | The base class of I/O devices
QIconDrag | Supports drag and drop operations within a QIconView
QIconDragItem | Encapsulates a drag item
QIconSet | Set of icons with different styles and sizes
QIconView | Area with movable labelled icons
QIconViewItem | Single item in a QIconView
QImage | Hardware-independent pixmap representation with direct access to the pixel data
QImageConsumer | Abstraction used by QImageDecoder
QImageDecoder | Incremental image decoder for all supported image formats
QImageDrag | Drag and drop object for transferring images
QImageFormat | Incremental image decoder for a specific image format
QImageFormatPlugin | Abstract base for custom image format plugins
QImageFormatType | Factory that makes QImageFormat objects
QImageIO | Parameters for loading and saving images
QInputDialog | Simple convenience dialog to get a single value from the user
QIntCache | Template class that provides a cache based on long keys
QIntCacheIterator | Iterator for QIntCache collections
QIntDict | Template class that provides a dictionary based on long keys
QIntDictIterator | Iterator for QIntDict collections
QIntValidator | Validator which ensures that a string contains a valid integer within a specified range
QJisCodec | Conversion to and from JIS character sets
QKeyEvent | Describes a key event
QKeySequence | Encapsulates a key sequence as used by accelerators
QLCDNumber | Displays a number with LCD-like digits
QLabel | Text or image display
QLayout | The base class of geometry managers
QLayoutItem | Abstract item that a QLayout manipulates
QLayoutIterator | Iterators over QLayoutItem
QLibrary | Wrapper for handling shared libraries
QLineEdit | One-line text editor
QListBox | List of selectable, read-only items
QListBoxItem | The base class of all list box items
QListBoxPixmap | List box items with a pixmap and optional text
QListBoxText | List box items that display text
QListView | Implements a list/tree view
QListViewItem | Implements a list view item
QListViewItemIterator | Iterator for collections of QListViewItems
QLocalFs | Implementation of a QNetworkProtocol that works on the local file system
QLock | Wrapper for a System V shared semaphore
QMainWindow | Main application window, with a menu bar, dock windows (e.g. for toolbars), and a status bar
QMap | Value-based template class that provides a dictionary
QMapConstIterator | Iterator for QMap
QMapIterator | Iterator for QMap
QMemArray | Template class that provides arrays of simple types
QMenuBar | Horizontal menu bar
QMenuData | Base class for QMenuBar and QPopupMenu
QMessageBox | Modal dialog with a short message, an icon, and some buttons
QMetaObject | Meta information about Qt objects
QMetaProperty | Stores meta data about a property
QMimeSource | Abstraction of objects which provide formatted data of a certain MIME type
QMimeSourceFactory | Extensible provider of mime-typed data
QMotifPlusStyle | More sophisticated Motif-ish look and feel
QMotifStyle | Motif look and feel
QMouseEvent | Parameters that describe a mouse event
QMoveEvent | Event parameters for move events
QMovie | Incremental loading of animations or images, signalling as it progresses
QMutex | Access serialization between threads
QNPInstance | QObject that is a Web-browser plugin
QNPStream | Stream of data provided to a QNPInstance by the browser
QNPWidget | QWidget that is a Web-browser plugin window
QNPlugin | The plugin central factory
QNetworkOperation | Common operations for network protocols
QNetworkProtocol | Common API for network protocols
QObject | The base class of all Qt objects
QObjectCleanupHandler | Watches the lifetime of multiple QObjects
QObjectList | QPtrList of QObjects
QObjectListIt | Iterator for QObjectLists
QPNGImagePacker | Creates well-compressed PNG animations
QPaintDevice | The base class of objects that can be painted
QPaintDeviceMetrics | Information about a paint device
QPaintEvent | Event parameters for paint events
QPainter | Does low-level painting e.g. on widgets
QPair | Value-based template class that provides a pair of elements
QPalette | Color groups for each widget state
QPen | Defines how a QPainter should draw lines and outlines of shapes
QPicture | Paint device that records and replays QPainter commands
QPixmap | Off-screen, pixel-based paint device
QPixmapCache | Application-global cache for pixmaps
QPlatinumStyle | Mac/Platinum look and feel
QPoint | Defines a point in the plane
QPointArray | Array of points
QPopupMenu | Popup menu widget
QPrinter | Paint device that paints on a printer
QProcess | Used to start external programs and to communicate with them
QProgressBar | Horizontal progress bar
QProgressDialog | Feedback on the progress of a slow operation
QPtrCollection | The base class of most pointer-based Qt collections
QPtrDict | Template class that provides a dictionary based on void* keys
QPtrDictIterator | Iterator for QPtrDict collections
QPtrList | Template class that provides doubly-linked lists
QPtrListIterator | Iterator for QPtrList collections
QPtrQueue | Template class that provides a queue
QPtrStack | Template class that provides a stack
QPtrVector | Template collection class that provides a vector (array)
QPushButton | Command button
QRadioButton | Radio button with a text or pixmap label
QRangeControl | Integer value within a range
QRect | Defines a rectangle in the plane
QRegExp | Pattern matching using regular expressions
QRegExpValidator | Used to check a string against a regular expression
QRegion | Clip region for a painter
QResizeEvent | Event parameters for resize events
QSGIStyle | SGI/Irix look and feel
QScreen | And its descendants manage the framebuffer and palette
QScrollBar | Vertical or horizontal scroll bar
QScrollView | Scrolling area with on-demand scroll bars
QSemaphore | Robust integer semaphore
QServerSocket | TCP-based server
QSessionManager | Access to the session manager
QSettings | Persistent platform-independent application settings
QShowEvent | Event which is sent when a widget is shown
QSignal | Can be used to send signals for classes that don't inherit QObject
QSignalMapper | Bundles signals from identifiable senders
QSimpleRichText | Small displayable piece of rich text
QSize | Defines the size of a two-dimensional object
QSizeGrip | Corner-grip for resizing a top-level window
QSizePolicy | Layout attribute describing horizontal and vertical resizing policy
QSjisCodec | Conversion to and from Shift-JIS
QSlider | Vertical or horizontal slider
QSocket | Buffered TCP connection
QSocketDevice | Platform-independent low-level socket API
QSocketNotifier | Support for socket callbacks
QSound | Access to the platform audio facilities
QSpacerItem | Blank space in a layout
QSpinBox | Spin box widget (spin button)
QSplitter | Implements a splitter widget
QSql | Namespace for Qt SQL identifiers that need to be global-like
QSqlCursor | Browsing and editing of SQL tables and views
QSqlDatabase | Used to create SQL database connections and provide transaction handling
QSqlDriver | Abstract base class for accessing SQL databases
QSqlDriverPlugin | Abstract base for custom QSqlDriver plugins
QSqlEditorFactory | Used to create the editors used by QDataTable and QSqlForm
QSqlError | SQL database error information
QSqlField | Manipulates the fields in SQL database tables and views
QSqlFieldInfo | Stores meta data associated with a SQL field
QSqlForm | Creates and manages data entry forms tied to SQL databases
QSqlIndex | Functions to manipulate and describe QSqlCursor and QSqlDatabase indexes
QSqlPropertyMap | Used to map widgets to SQL fields
QSqlQuery | Means of executing and manipulating SQL statements
QSqlRecord | Encapsulates a database record, i.e. a set of database fields
QSqlRecordInfo | Encapsulates a set of database field meta data
QSqlResult | Abstract interface for accessing data from SQL databases
QStatusBar | Horizontal bar suitable for presenting status information
QStoredDrag | Simple stored-value drag object for arbitrary MIME data
QStrIList | Doubly-linked list of char* with case-insensitive comparison
QStrList | Doubly-linked list of char*
QStrListIterator | Iterator for the QStrList and QStrIList classes
QString | Abstraction of Unicode text and the classic C null-terminated char array
QStringList | List of strings
QStyle | The look and feel of a GUI
QStyleFactory | Creates QStyle objects
QStyleOption | Optional parameters for QStyle functions
QStylePlugin | Abstract base for custom QStyle plugins
QStyleSheet | Collection of styles for rich text rendering and a generator of tags
QStyleSheetItem | Encapsulation of a set of text styles
QTab | The structures in a QTabBar
QTabBar | Tab bar, e.g. for use in tabbed dialogs
QTabDialog | Stack of tabbed widgets
QTabWidget | Stack of tabbed widgets
QTable | Flexible editable table widget
QTableItem | The cell content for QTable cells
QTableSelection | Access to a selected area in a QTable
QTabletEvent | Parameters that describe a Tablet event
QTextBrowser | Rich text browser with hypertext navigation
QTextCodec | Conversion between text encodings
QTextCodecPlugin | Abstract base for custom QTextCodec plugins
QTextDecoder | State-based decoder
QTextDrag | Drag and drop object for transferring plain and Unicode text
QTextEdit | Powerful single-page rich text editor
QTextEncoder | State-based encoder
QTextIStream | Convenience class for input streams
QTextOStream | Convenience class for output streams
QTextStream | Basic functions for reading and writing text using a QIODevice
QThread | Platform-independent threads
QTime | Clock time functions
QTimeEdit | Time editor
QTimer | Timer signals and single-shot timers
QTimerEvent | Parameters that describe a timer event
QToolBar | Movable panel containing widgets such as tool buttons
QToolButton | Quick-access button to commands or options, usually used inside a QToolBar
QToolTip | Tool tips (balloon help) for any widget or rectangular part of a widget
QToolTipGroup | Collects tool tips into related groups
QTranslator | Internationalization support for text output
QTranslatorMessage | Translator message and its properties
QTsciiCodec | Conversion to and from the Tamil TSCII encoding
QUriDrag | Drag object for a list of URI references
QUrl | URL parser and simplifies working with URLs
QUrlInfo | Stores information about URLs
QUrlOperator | Common operations on URLs
QVBox | Vertical geometry management of its child widgets
QVBoxLayout | Lines up widgets vertically
QVButtonGroup | Organizes QButton widgets in a vertical column
QVGroupBox | Organizes a group of widgets in a vertical column
QValidator | Validation of input text
QValueList | Value-based template class that provides doubly linked lists
QValueListConstIterator | Const iterator for QValueList
QValueListIterator | Iterator for QValueList
QValueStack | Value-based template class that provides a stack
QValueVector | Value-based template class that provides a dynamic array
QVariant | Acts like a union for the most common Qt data types
QWMatrix | 2D transformations of a coordinate system
QWSDecoration | Allows the appearance of the Qt/Embedded Window Manager to be customized
QWSKeyboardHandler | Implements the keyboard driver/handler for Qt/Embedded
QWSMouseHandler | Mouse driver/handler for Qt/Embedded
QWSServer | Server-specific functionality in Qt/Embedded
QWSWindow | Server-specific functionality in Qt/Embedded
QWaitCondition | Allows waiting/waking for conditions between threads
QWhatsThis | Simple description of any widget, i.e. answering the question "What's this?"
QWheelEvent | Parameters that describe a wheel event
QWidget | The base class of all user interface objects
QWidgetFactory | For the dynamic creation of widgets from Qt Designer .ui files
QWidgetItem | Layout item that represents a widget
QWidgetPlugin | Abstract base for custom QWidget plugins
QWidgetStack | Stack of widgets of which only the top widget is user-visible
QWindowsMime | Maps open-standard MIME to Window Clipboard formats
QWindowsStyle | Microsoft Windows-like look and feel
QWizard | Framework for wizard dialogs
QWorkspace | Workspace window that can contain decorated windows, e.g. for MDI
QXmlAttributes | XML attributes
QXmlContentHandler | Interface to report the logical content of XML data
QXmlDTDHandler | Interface to report DTD content of XML data
QXmlDeclHandler | Interface to report declaration content of XML data
QXmlDefaultHandler | Default implementation of all XML handler classes
QXmlEntityResolver | Interface to resolve external entities contained in XML data
QXmlErrorHandler | Interface to report errors in XML data
QXmlInputSource | The input data for the QXmlReader subclasses
QXmlLexicalHandler | Interface to report the lexical content of XML data
QXmlLocator | The XML handler classes with information about the parsing position within a file
QXmlNamespaceSupport | Helper class for XML readers which want to include namespace support
QXmlParseException | Used to report errors with the QXmlErrorHandler interface
QXmlReader | Interface for XML readers (i.e. parsers)
QXmlSimpleReader | Implementation of a simple XML reader (parser)
QXtApplication | Facilitates the mixing of Xt/Motif and Qt widgets
QXtWidget | Allows mixing of Xt/Motif and Qt widgets
Qt | Namespace for miscellaneous identifiers that need to be global-like


Qt Class Chart

The gzipped postscript A3 size master copy of the class chart is available for download from ftp://ftp.trolltech.com/qt/pdf/3.0/qt30-class-chart.pdf (104K).* The PDF file will always be the same or more recent than the one shown here.

* The PDF file is not supported; we do not guarantee it will print correctly (although several people have reported that it does). It is not available in any other format or size.


画布模块

这个模块是Qt企业版的一部分。

画布模块提供了一个名为QCanvas的高度优化的二维绘图区。 画布可以有任意数量的QCanvasItems。画布项则可以有任意的形状、尺寸和内容，在画布中能自由的移动，并且能被检查出是否有冲突。画布项能被设置成在画布中自动地移动以及使画布项支持QCanvasSprite。（如果你需要三维绘图请看Qt的OpenGL模块。）

画布模块使用文档/视图模型。QCanvasView 类是被用来显示画布的特定视图。多视图能同时在同一画布中显示。每一个视图在画布中使用一个任意的变换矩阵，以便能使其容易的实现诸如缩放的特性。

Screenshot of a canvas

Qt提供了一系列预定义的QCanvas项，如下所示:

  • QCanvasItem--一个所有画布项的抽象基类。
  • QCanvasEllipse--椭圆或者“饼的部分”。
  • QCanvasLine--线条部分。
  • QCanvasPolygon--多边形。
  • QCanvasPolygonalItem--一个含有非矩形形状的基类。大多数画布项都派生于此类。
  • QCanvasRectangle--矩形。此类矩形不能被倾斜或旋转。绘制可旋转的矩形使用QCanvasPolygon。
  • QCanvasSpline--多重贝塞尔曲线。
  • QCanvasSprite--活动的图片。
  • QCanvasText--文本字符串。

QCanvasPixmap和QCanvasPixmapArray这两个类是由QCanvasSprite类来显示在画布上的活动和移动的图片。

更多的专门的项能够通过继承画布项类来实现。从一个QCanvasItem的派生类（通常为 QCanvasPolygonalItem）来实现比直接从QCanvasItem继承更容易。

Copyright © 2002 TrolltechTrademarks
译者：dirtfei
Qt version 3.0.5


调试技术

现在我们为您的基于Qt的软件的调试提供一些有用的提示。

命令行参数

当你运行Qt程序时，你可以指定几个命令行参数来帮助你调试。

  • -nograb 应用程序不再捕获鼠标或者键盘。当程序在Linux下运行在gdb调试器中时这个选项是默认的。
  • -dograb 忽略任何隐含的或明显得-nograb。即使-nograb出现在命令行的最后，-dograb也会超过-nograb生效的。
  • -sync 在X同步模式下运行应用程序。同步模式强迫X服务器立即执行每一个X客户端的请求，而并不能使用缓存优化。它使得程序更加容易测试并且通常会更慢。-sync模式只对X11版本的Qt有效。

警告和调试消息

Qt包含了三个全局函数来写出警告和调试文本。

  • qDebug()用来为测试及其它写调试输出。
  • qWarning()用来在程序发生错误时写警告输出。
  • qFatal()用来写致命错误消息并且退出。

这些函数的Qt实现是在Unix/X11下把文本打印到标准错误（stderr）输出，在Windows下会打印到调试器。你可以通过安装一个消息处理器，qInstallMsgHandler()来接收这些函数。

当应用程序看起来或者用起来很奇怪的时候，调试函数QObject::dumpObjectTree()和QObject::dumpObjectInfo()很有用。如果你使用了对象名称，这将会更有用，但通常情况下是没有名称的。

调试宏

qglobal.h头文件包含了很多调试宏和#defines。

两个重要的宏是：

  • Q_ASSERT(b)里面的b是一个布尔表达式，当b是FALSE的时候，写出警告信息：“ASSERT: 'b' in file file.cpp (234)”。
  • Q_CHECK_PTR(p)里面的p是一个指针。如果p是空的话，写出警告信息：“In file file.cpp, line 234: Out of memory”。

这些宏在检测程序错误时很有用，比如像这样：

  char *alloc( int size )
  {
      Q_ASSERT( size > 0 );
      char *p = new char[size];
      Q_CHECK_PTR( p );
      return p;
  }

如果你定义了QT_FATAL_ASSERT标记，Q_ASSERT将会调用fatal()而不是warning()，所以一个错误声明将会导致在打印错误消息后使程序退出。

注意如果QT_CHECK_STATE未定义，Q_ASSERT宏就是一个空的表达式（参见下面）。在里面的任何代码都不会被执行。相似的，如果QT_CHECK_NULL未定义，Q_CHECK_PTR也是一个空的表达式。这里就是一个不应该如此使用Q_ASSERT和Q_CHECK_PTR的例子：

  char *alloc( int size )
  {
      char *p;
      Q_CHECK_PTR( p = new char[size] ); // WRONG
      return p;
  }

这个问题是棘手的：仅仅在正确的检测标记被定义时，p才会被设置为健全的值。如果QT_CHECK_NULL标记没有被定义，代码被编译了，在Q_CHECK_PTR表达式中的代码是不会被执行的（正确地，因为它仅仅用于调试目的）并且会分配一个疯狂的指针。

Qt库包含了几百个内部检查，当一些错误被检测出时，会打印警告信息。

Qt中的健全测试和作为结果的警告信息是有条件的，基于不同的调试标记的状态：

  • QT_CHECK_STATE：检测一致的/期望的对象状态
  • QT_CHECK_RANGE：检测变量范围错误
  • QT_CHECK_NULL：检测危险的空指针
  • QT_CHECK_MATH：检测危险的数学，比如被0除
  • QT_NO_CHECK：关闭所有的QT_CHECK_...标记
  • QT_DEBUG：使调试代码生效
  • QT_NO_DEBUG：关闭QT_DEBUG标记

默认情况下，QT_DEBUG和所有的QT_CHECK标记都是打开的。如果要关闭QT_DEBUG，请定义QT_NO_DEBUG。如果要关闭QT_CHECK标记，请定义QT_NO_CHECK。

实例：

  void f( char *p, int i )
  {
  #if defined(QT_CHECK_NULL)
      if ( p == 0 )
          qWarning( "f: Null pointer not allowed" );
  #endif

  #if defined(QT_CHECK_RANGE)
      if ( i < 0 )
          qWarning( "f: The index cannot be negative" );
  #endif
  }

普通的Bug

这是一个如此普通的bug，所以要在这里提到：如果你你在类生命中包含了Q_OBJECT宏并且运行了moc，但是忘记了把moc生成的对象代码连接到你的可执行程序中，你就会得到非常困惑的错误消息。

任何一个会提示缺乏vtbl、_vtbl、__vtbl或者和这个类似的连接错误都有可能是这样的问题。

Copyright © 2002 Trolltech Trademarks 译者:Cavendish
Qt 3.0.5版


前言

介绍

这本参考手册是有关于Qt设计器的，Qt设计器是用来设计和实现用户界面并能够在多平台下使用的一种工具。Qt设计器可以使用户界面设计实验变得简单。在任何时候你可以要求所生成的代码去重建Qt设计器产生的用户界面文件，并可以根据你的喜好来改变你的设计。假如你使用的是先前的版本，你将发现在新的版本下自己可以立即进入工作，因为新的版本在界面上基本没有什么变化。但是你将发现根据你们的反馈而开发出的新的部件和新的或者改进的功能。

Qt设计器帮助你使用部局工具在运行时自动的移动和缩放你的部件（Windows中的术语控件）来构建用户界面。最终界面是既好用又好看，使最终用户拥有一个舒适的操作环境并且能够方便的进行参数选择。Qt设计器支持信号和槽机制以使部件间能够进行有效的通信。Qt设计器包含一个代码编辑器，使你能够在合成的代码里面嵌入自己定制的槽。那些更喜欢使用手工方法分解合成代码的朋友也能够继续使用基类，因为从第一版的Qt设计器开始就把这些基类移植进去了。

这本手册通过讲述开发例程来向你介绍Qt设计器。一开始的六章是设计指南，而且各自间都尽可能设计成是独立的。接下来要介绍的是除了首章以外的每一章，并假定你已经熟悉了第一章的内容，该章包含使用Qt设计器创建一个Qt应用程序的基础。以下是便各章的简要概述：

  • 第一章，创建一个Qt应用程序，通过带着你一步一步的创建一个小但功能完整的应用程序来介绍Qt设计器的使用。按照着这种方法你将学到如何创建一个窗体并且向窗体中添加部件。在你阅读这一章的过程中你将使用窗体和属性编辑器来定制你的应用程序，并且学习怎样使用部局工具来对一个窗体进行部局。你也将学到如何使用信号和槽机制和Qt设计器的内建代码编辑器来制造应用程序的各种功能。我们也将解释如何使用qmake来生成Makefile，以致于你能够编译和运行应用程序。

  • 第二章，创建含有工具栏和菜单的主窗口，我们将创建一个简单的文本编辑器。通过写这个应用程序你将学到如何使用菜单栏和工具栏来创建一个主窗口。我们将看到如何使用Qt的内建功能来处理一般任务(e.g. 复制粘贴操作)还将看到如何为我们自己的菜单栏选项和工具栏按钮创建我们自己的功能。

  • 第三章，走近设计器，提供有关Qt设计器的信息如相关的开发应用程序，并且还对Qt设计器背后的一些基本原理进行解释。

  • 第四章，派生类和动态对话框， 将展示如何派生一个窗体；这将让你清楚的通过执行关键代码的功能来分解用户界面。本章中还附加有关qmake和 uic的信息。本章也将阐述如何使用QWidgetFactory把.ui文件放进你的应用程序从而动态的加载对话框和如何访问这些对话框的部件和派生部件。

  • 第五章，创建自定义窗口部件，告诉你如何才能创建自定义部件。既有在第一版的Qt设计器中就被介绍的简单方法，又有像利用插件这种新的更有效的的方法都在这一章里被介绍了。

  • 第六章， 创建数据库应用程序介绍了Qt的SQL类并且带着你通过一个实例来演示如何执行查询和如何设置主要关系的细节，深入讲解和处理外关键字。

  • 第七章，定制和集成Qt设计器，聚焦Qt设计器本身，向你展示如何定制设计器，如何使用可视化工作室集成设计器和如何创建一个Makefiles。

这剩下的章节提供了一些参考资料，用以讲述Qt设计器的菜单选项、工具栏、快捷键以及对话框等的细节。

你所应该知道的

该手册假定你已经有了一些有关C++和Qt应用程序开发框架的基础。假如你需要学习C++或者Qt，这儿有大量的C++的书可供使用和少量的但是数量却在不断增长的有关Qt的书。你可以尝试一下大量伴随着Qt的联机文档和许多例程。

企业版的Qt包含了SQL模块。在创建数据库应用程序一章里我们演示了如何使用Qt设计器来编写SQL应用程序；这一章需要一些SQL和关系数据库的知识。

Qt设计器中的新东西

该版本的Qt设计器较其前一版本来说增加了更加多的功能。自己定制的槽功能代码可以直接在Qt设计器中编辑；操作工具栏、菜单栏就可以创建主窗口了；部局可以结合使用分解器；一些插件还允许你把大量的自定义部件进行打包并且在Qt设计器中可以使用他们。从对用户界面微小的改善到提高效率还有很多其它增强功能被结使在里面，例如在一个应用程序里的所有窗体可以有效的共享像素映射。

该版本的Qt设计器创建的工程文件使得开关在一个应用程序中的所有窗体变得十分简单，而且仍然保持了一个通常的数据库设置和映象。通过对派生类的全面支持，为直接在Qt设计器中编写代码带来了很多的益处，这些知识已经全面涵盖在走近设计器一章中了。

还介绍了一个新的库libqui，该库允许你在运行时从Qt设计器的.ui文件中自动加载对话框。这允计你提供给你的应用程序用户相当可观的自定义界面自由度，否则就需要使用C++了。

如果你仅仅想要一个简单而功能强大的单对话框可视设计工具，虽然新版本的Qt设计器介绍了新的进阶和技术但你可以忽略这些方面并且正确的使用与Qt 2.x相同的方法。

Qt设计器

反馈

如果你关于这个手册有一些注释、建议、批评或者适当的赞美，请访问doc@trolltech.com让我们知道。关于Qt或者Qt设计器的bug报告可以发送至Qt-bugs@trolltech.com。你也许也想要加入专门由开发者阅读和捐献的Qt-interest邮件列表；请访问http://www.trolltech.com以了解更多的细节。

[Qt设计器首页] [下一章：创建一个Qt应用程序]

Copyright © 2002 Trolltech Trademarks 译者:hackerjun
Qt 3.0.5版


Creating a Qt Application

Starting and Exiting Qt Designer

Qt Designer is controlled in the same way as any other modern desktop application. To start Qt Designer under Windows click the Start button and click Programs|Qt X.x.x|Designer. (X.x.x is the Qt version number, e.g. 3.0.0.) If you're running a Unix or Linux operating system you can either double click the Qt Designer icon or enter designer & in an xterm.

When you've finished using Qt Designer click File|Exit; you will be prompted to save any unsaved changes. Help is available by pressing F1 or from the Help menu.

To get the most benefit from the tutorial chapters we recommend that you start Qt Designer now and create the example applications as you read. Most of the work involves using Qt Designer's menus, dialogs and editors, with only small amounts of code to type in.

When you start Qt Designer, by default, you will see a menu bar and various toolbars at the top. On the left hand side are three windows, the first is the Files window, the second is the Widgets and Source window (the Object Explorer) and the third is the Properties window. The Files window lists the files and images associated with the project; to open any form single click it in the Files list. The Widgets and Source window lists the current form's widgets and slots. The Properties window is used to view and change the properties of forms and widgets. We will cover the use of Qt Designer's windows, dialogs, menu options and toolbar buttons as we create example applications.

In this chapter we will build an application called 'multiclip' which allows you to store and retrieve multiple text clippings to and from the clipboard.

The Multiclip Application

Creating a New Project

Whenever you create a new application we strongly recommend that you create a project file and open the project rather than individual .ui files. Using a project has the advantage that all the forms you create for the project are available via a single mouse click rather than having to be loaded individually through file open dialogs. An additional benefit of using project files is that they allow you to store all your images in a single file rather than duplicate them in each form in which they appear. See The Designer Approach chapter's Project management section for detailed information on the benefits of using project files.

Start Qt Designer if you haven't already. Click File|New to invoke the New File dialog. Click the 'C++ Project' icon, then click OK to invoke the Project Settings dialog. You need to give the project a name, and we recommend that you put each project in its own subdirectory. Click the ellipsis ... button to invoke the Save As dialog and navigate to where you want to put the new project. Click the Create New Folder toolbar button to create the 'multiclip' directory. Double click the 'multiclip' directory to make it the current directory. Enter a file name of 'multiclip.pro', and click the Save button. The 'Project File' field of the Project Settings dialog will have the path and name of your new project; click OK to create the project.

Creating a New Project

The name of the current project is shown in the Files toolbar which is the top left toolbar by default. Once we have a project we can add forms and begin to build our application. (See Customizing Qt Designer for information on changing Qt Designer's toolbars and windows to suit your preferences.)

Creating a New Form

Click File|New to invoke the New File dialog. Several default forms are supplied but we will use the default Dialog form, so just click OK. A new form called 'Form1' will appear. Note that the new form is listed in the Files list and the Properties window shows the form's default property settings.

Click the Value beside the name property and change the form's name to 'MulticlipForm'. Change the form's caption to 'Multiclip'. The properties are ordered in accordance with the inheritance hierarchy, and caption is roughly in the middle of the property editor. Save the form: click File|Save, enter the name 'multiclip.ui', then click the Save button.

Creating a New Form

Using the Property Editor

The Property Editor has two columns, the Property column which lists property names and the Value column which lists the values. Some property names have a plus sign '+' in a square to their left; this signifies that the property name is the collective name for a set of related properties. Click the form to make the Property Editor show the form's properties. Click the sizePolicy property's plus sign; you will see four properties appear indented below sizePolicy, hSizeType, vSizeType, horizontalStretch and verticalStretch. These properties are edited in the same way as any other properties.

Property Editor

Some properties have simple values, for example, the name property has a text value, the width property (within minimumSize for example) has a numeric value. To change a text value click the existing text and type in your new text. To change a numeric value click the value and either type in a new number, or use the spin buttons to increase or decrease the existing number until it reaches the value you want. Some properties have a fixed list of values, for example the mouseTracking property is boolean and can take the values True or False. The cursor property also has a fixed list of values. If you click the cursor property or the mouseTracking property the value will be shown in a drop down combobox; click the down arrow to see what values are available. Some properties have complex sets of values; for example the font property. If you click the font property an ellipsis button (...) will appear; click this button and a Select Font dialog will pop up which you can use to change any of the font settings. Other properties have ellipsis buttons which lead to different dialogs depending on what settings the property can have. For example, if you have a lot of text to enter for a text property you could click the ellipsis button to invoke the multi-line text editor dialog.

The names of properties which have changed are shown in bold. If you've changed a property but want to revert it to its default value click the property's value and then click the red 'X' button to the right of the value. Some properties have an initial value, e.g. 'TextEdit1', but no default value; if you revert a property that has an initial value but no default value (by clicking the red 'X') the value will become empty unless the property, e.g. name, is not allowed to be empty.

If multiple widgets are selected, the property editor shows the properties that the selected widgets have in common. Changing one of these properties will cause all the selected widgets to have this property changed.

The property editor fully supports Undo and Redo (Ctrl+Z and Ctrl+Y, also available from the Edit menu).

Adding Widgets

The multiclip application consists of a text box to display the current clipboard text (if any), a list box showing the previous clippings, a length indicator, a checkbox and buttons. If you run the application and resize it all the widgets will scale properly.

The Qt Designer approach to laying out a form is to place the required widgets on the form in the approximate positions that they should occupy and then use the layout tools to size and position them correctly. We'll now add the multiclip form's widgets.

  1. We'll start with the current clipping text box. Click the Text Label toolbar button and click towards the top left of the form. (If you hover the mouse over a toolbar button its name will appear in a tooltip.) We won't bother renaming the label since we'll never refer to it in code; but we need to change its text, so change its text property to 'Current Clipping'. (See the Using the Property Editor sidebar for an explanation of the property editor.)

    Click the Line Edit toolbar button and click towards the top right of the form. Use the Property Editor to change the widget's name to 'currentLineEdit'.

  2. Now we'll add another label and the list box. Click the Text Label toolbar button and click below the Current Clipping label. Change the text property to 'Previous Clippings'. Don't worry about positioning the widgets precisely, nor about the fact that they are the wrong size; the layout tools (covered in the next section) will take care of this.

    Click the List Box toolbar button and click the form below the 'Previous Clippings' label. Change the list box's name to 'clippingsListBox'. By default Qt Designer creates list boxes with a single initial value of 'New Item'. We don't want this value (we'll be populating our list box in code later), so we need to remove the value. Right click the list box then click the Edit menu item on the popup menu to invoke the listbox's value editor dialog. Click Delete Item to delete the default item, then click OK. (See the Value Editors sidebar.)

  3. We want to know the length of the current clipping so we'll add a label and an LCD Number widget.

    Click the Text Label toolbar button and click below the Line Edit. Change its text property's value to 'Length'. Click the LCD Number toolbar button and click below the length label. Change the LCD Number's name to 'lengthLCDNumber'.

  4. Multiclip can be made to detect clipboard changes and automatically add new clippings. We want the user to have control over whether this should happen or not so we will provide a check box which they can use to indicate their preference.

    Click the Check Box toolbar button and click below the LCD Number. Change the checkbox's name to 'autoCheckBox' and its text to 'A&uto Add Clippings'. Note that the accel property automatically changes to Alt+U because the ampersand in the text signifies a keyboard shortcut.

  5. The last widgets we require are the buttons. One way to add the same kind of widget multiple times is to add one, copy it, then paste repeatedly. We will use another approach.

    Double click the Push Button toolbar button; now click below the checkbox to place a button. Click below the button we've just added to add a second button. Add a third and fourth button. Now click the Pointer toolbar button to switch off automatically adding the same widget. Change the first button's name to 'addPushButton' and its text to '&Add Clipping'. Change the second button's name to 'copyPushButton' and its text to '&Copy Previous'. Change the third button's name and text properties to 'deletePushButton' and '&Delete Clipping' respectively. Similarly change the fourth button's name and text to 'quitPushButton' and '&Quit'.

All our widgets have been placed on the form with their properties changed to suit our application's needs. In the next section we will use Qt Designer's layout tools to size and position the widgets correctly and in such a way that when the user resizes the form the widgets will scale properly.

Adding Widgets to the Form

Value Editors

Whilst the Property Editor is used to customize the generic properties of widgets, value editors are used to edit values held within instances of particular widgets. For example a QLineEdit can only contain a single line of text, but a QListBox can contain any number of items each of which may be a line of text, a pixmap, or both. To invoke a widget's value editor double click the widget. (Alternatively right click the widget and a popup menu will appear; if the first menu item is 'Edit', you can click this to access the widget's value editor dialog.) Different widgets have different value editors. See the Value Editors chapter for more details.

Laying Out Widgets and Previewing

Introduction to Layouts

Layouts work by grouping together widgets and groups of widgets, horizontally, vertically or in a grid. Widgets that are laid out together horizontally or vertically can be grouped either with a Layout or with a Splitter; the only difference is that a user can manipulate a Splitter themselves.

If we want to lay out some widgets side by side we would select them and then click the Lay Out Horizontally toolbar button. If we want our widgets to be lined up one above the other we would use the Lay Out Vertically toolbar button. Once we've grouped some widgets together we can then lay out the groups in relation to each other, again using vertical, horizontal or grid layouts. Once we have a collection of laid out groups we then click on the form itself and lay out the groups within the form using one of the layout buttons.

Some widgets will grow to fill the available space, vertically or horizontally or both ways. Buttons and line edits will fill horizontal space for example, whereas a ListView will fill space in both directions. The easiest way to achieve the layout you want is to use Qt Designer's layout tools. When you apply a layout to some widgets in some situations the widgets may not lay out the way you want. If a widget does not fill up enough space try changing its sizePolicy to Expanding. If a widget takes up too much space one approach is to change its sizePolicy, and another approach is to use a Spacer to consume excess space.

Spacers have no visual appearance on the running form and are used purely to insert space between widgets or groups of widgets. Suppose you have a widget that takes up too much space. You could break the layout and resize the widget to make room for a spacer. Then you would insert the spacer and layout the spacer with the widgets and the spacer will consume the excess space. If the spacer doesn't take up the right amount of space you can change its sizePolicy for finer control.

The best way to learn about layouts and spacers is to try them out. Experimenting with layouts is easy. If you make any changes that you aren't happy with you can easily undo them by clicking Edit|Undo or by pressing Ctrl+Z. In the next section we'll lay out our multiclip example step-by-step.

Laying Out Widgets

Layouts provide a means of grouping widgets and groups of widgets together in horizontal and vertical pairs and in grids. If you use layouts your forms and the widgets they contain will scale automatically when the user resizes the window. This is better than using absolute sizes and positions since you don't have to write any code to achieve the scaling and your users can make the most of their screen size whether they have a laptop or a very large screen desktop machine. Layouts use standard sizes for margins and widget spacing which helps give your applications a consistent and proportional look without requiring any effort on your part. Layouts are also easier and faster to use than absolute positioning; you can just place your widgets on the form in approximate positions and leave the layout tools to size and scale the widgets correctly.

Selecting Widgets and Inserting Widgets

To select an individual widget, either click the widget itself or click its Name in the Object Explorer window. To select a group either click a fraction outside its red outline or click its Name in the Object Explorer window. To select multiple widgets or groups, click the form to deselect any selected widgets, then Ctrl+Click one widget or group then drag the rubber band so that it touches the other widgets or groups that you want to select. This technique is particularly useful for selecting widgets that are inside another widget. For example to select the radio buttons in a button group but not the button group itself you would click the form then Ctrl+Click one of the radio buttons and drag the rubber band to touch the other radio buttons.

If we want to insert a widget into a gap between widgets which are in a layout we can click the toolbar button for the new widget and then click in the gap. Qt Designer will ask us if we want to break the layout and if we click Break Layout the layout will be broken and our widget inserted. We can then select the widgets and groups we want to lay out and lay them out again. The same effect can be achieved by clicking the group and either clicking the Break Layout toolbar button or pressing Ctrl+B.

The layout we want to achieve is to have the current clipping label and currentLineEdit side by side at the top of the form. We want the previous clippings label and the clippingsListBox to occupy the left hand side of the form with the remaining widgets in a column on the right. We want to divide left and right with a splitter and make the left hand side larger by default. We'll leave the sizing of the widgets to Qt Designer. The layout controls are in the Layout toolbar. (By default this is the fourth toolbar counting left to right.) We'll now lay out the widgets we've placed on the form.

  1. Click the current clipping label and Shift+Click the currentLineEdit Line Edit. (Shift+Click means hold down the shift key whilst clicking; this will ensure that Qt Designer performs multiple selections.) Most of the layout toolbar buttons will now be available. Click the Lay Out Horizontally toolbar button. (If you hover the mouse over a toolbar button a tooltip giving the button's name will appear.) The two widgets will be moved together with a thin red line surrounding them. It doesn't matter that the widgets aren't the right size or in exactly the right place; as we progress with the layout Qt Designer will size and place them correctly.

    Layout Current Clipping Label and currentLineEdit

  2. Click the Previous Clippings label and Shift+Click the clippingsListBox. Click the Lay Out Vertically toolbar button.

  3. We want the remaining widgets to be grouped together vertically. We could Shift+Click each one but instead click the form above the Length label, then drag until the Length label, the LCD Number, the check box and all the buttons are all touching the rubber band (a black outline rectangle) that appears when you drag. Release the mouse, and all the remaining widgets should be selected. If you missed any Shift+Click them. Now click the Lay Out Vertically toolbar button.

    Selecting a Group of Widgets

We now have three groups of widgets which must be laid out in relation to each other and then laid out in relation to the form itself.

Groups of Layed Out Widgets

  1. Shift+Clicking is used to select individual widgets. To select a group we must click the form to deselect any selected widgets, then Ctrl+Click the group and drag so that the rubber band touches the groups we want to lay out and then release. With the buttons and other widgets already laid out and selected, Ctrl+Click the list box and drag the rubber band over the one of the buttons, then release. Both groups should now be selected. Click the Lay Out Horizontally (in Splitter) toolbar button.

    Layout Groups of Widgets

  2. We now have two groups, the top one with the Current Clipping label and the line edit and the group we've just created with the list box, buttons and other widgets. We now want to lay these out in relation to the form. Click the form and click the Lay Out Vertically toolbar button. The widgets will be resized to fill the entire form.

    Lay out Widgets in Relation to the Form

Unfortunately the Length label and the LCD Number take up far too much space, so we will have to revise the layout. With experience you will find that you do not need to rework layouts very often. We will insert a spacer which will use the extra space.

  1. First we must make some room for the spacer. Click the LCD Number to select it. Now click the Break Layout toolbar button. Move the LCD Number up a little bit, there's no need to be exact we just want to create some space below it.

  2. Now we'll add the spacer. Click the Spacer toolbar button, then click the form in the space you've created between the LCD Number and the check box. A popup menu with two options, Horizontal and Vertical, will appear; click Vertical. We choose vertical because we want the spacer to consume excess vertical space.

    Adding a Vertical Spacer

  3. We need to regroup the buttons and other widgets in a vertical group. Drag the mouse from near the bottom right of the form so that the rubber band includes or touches the buttons, the check box, the spacer, the LCD Number and the Length label; then release. If you selected any other widgets by mistake, click the form and try the drag again. Click the Lay Out Vertically toolbar button.

  4. We now have three groups as we had before, only this time with the small addition of the spacer. Select the list box and the buttons by clicking the form, dragging and releasing once the rubber band covers or touches both groups. Click Lay Out Horizontally (in Splitter) to regroup them with the splitter.

  5. The last step is to lay out the form itself. Click the form and click Lay Out Vertically. The form should now be laid out correctly.

    Lay Out the Form

There are two small deficiencies in the layout that we have achieved. Firstly the list box and buttons take up an equal width whereas we'd rather have the list box take up about three quarters of the width. Secondly the Length label, the check box and the buttons extend right up to the splitter. They would look more attractive if there was a little bit of space separating them from the splitter.

Expanding the list box half of the splitter would require us to add an init() function with the following code:

    void MulticlipForm::init()
    {
    QValueList< int > sizes;
    sizes << 250 << 40;
    Splitter->setSizes( sizes );
    }

We won't add this code now since we'll deal with the code when we come to implement the application's functionality later in the chapter.

We will create some space around the splitter by changing the margins of the layout groups that it joins together. To click a layout either click a fraction above the layout's top red line or click the layout's name in the Object Explorer (the Widgets and Source window). (See Object Explorer Window sidebar for an explanation of the Object Explorer window.) Click the layout that contains the list box, and change the layoutMargin property to 6, then press Enter. Click the layout that contains the buttons and other widgets, and change its layoutMargin to the same value in the same way.

The Object Explorer

View the Object Explorer (Widgets and Source) window by clicking Window|Views|Object Explorer. The Object Explorer has two tabs, the Widgets tab which shows the object hierarchy, and the Source tab which shows the source code you have added to the form. Clicking the name of a widget in the Widget tab will select the widget and show its properties in the Property Editor. It is easy to see and select widgets in the Object Explorer which is especially useful for forms that have many widgets or which use layouts.

Object Explorer

In the original version of Qt Designer if you wanted to provide code for a form you had to subclass the form and put your code in the subclass. This version fully supports the subclassing approach, but now provides an alternative: placing your code directly into forms. Writing code in Qt Designer is not quite the same as subclassing, for example you cannot get direct access to the form's constructor or destructor. If you need code to be executed by the constructor create a slot called void init(); if it exists it will be called from the constructor. Similarly, if you need to be executed before destruction create a slot called void destroy(). You can also add your own class variables which will be put in the generated constructor's code, and you can add forward declarations and any includes you require. To add a variable or declaration right click the appropriate item, e.g. Class Variables, then click New then enter your text, e.g. QString fileName. If one or more items exist right clicking will popup a two item menu with New and Delete as options. To edit code just click the name of a function to invoke the code editor. Code editing and creating slots are covered later.

If you subclass the form you create your own .cpp files which can contain your own constructor, destructor, functions, slots, declarations and variables as your requirements dictate. (See Subclassing for more information.)

In the example we used Qt Designer's layout tools to lay out our widgets. We will use the layout tools again in the examples presented in later chapters. If you want to use absolute positioning, i.e. to place and size your widgets with exact pixel sizes you can easily do so. To place a widget click it and drag it to the desired position. To resize it, click it, and drag one of the sizing handles (these are small blue squares) until the size is right. To stop the widget from resizing when the window is resized change the hSizeType and vSizeType (these are properties within the sizePolicy property), to Fixed.

Previewing

Although Qt Designer presents an accurate view of our forms we often want to see what a form looks like when it is run. It is also useful to be able to test out some aspects of the form, for example how the form scales when resized or how the splitters work in practice. If we're building multiplatform applications it is also useful to see how the form will look in different environments.

To see a preview either click Preview|Preview Form or press Ctrl+T. To leave preview mode close the window in the standard way for your environment. To view previews which show how the application will look on other platforms click the Preview menu and click one of the menu items that drop down.

Preview the multiclip form and try out the splitter and try resizing the form. In all probability you moved the splitter to the right to reduce the size of the buttons to make the form more attractive. The splitter seemed like a good idea but in practice we want the buttons and the other widgets on the right hand side to take up a fixed amount of space. Qt Designer makes changing layouts very easy, so we'll fix this straight away.

Previewing Multiclip

Click the splitter then click the Break Layout toolbar button; the splitter will be removed. Now click the form itself, near the bottom, and drag the rubber band so that it touches both the list box and some of the buttons, then release. The list box group and the buttons group are selected; click the Lay Out Horizontally toolbar button. Click the form then click the Lay Out Vertically toolbar button. The form is now laid out as we require. Preview the form (press Ctrl+T) and try resizing it.

It would be useful if you experimented further with layouts since they work visually and are best learnt through practice. To remove a layout click the Break Layout toolbar button; to apply a layout select the relevant widgets or groups and click a layout button. You can preview as often as you like and you can always undo any changes that you make.

Let's try an experiment, to see how the grid layout works. Click the list box, then press Ctrl+B (break layout). Click one of the buttons and press Ctrl+B. Click the form at the bottom and drag until all the widgets are touching or within the rubber band, (but excluding the Current Clipping label and the currentLineEdit line edit); then release. Press Ctrl+G (lay out in a grid). Click the form, then click Ctrl+L (lay out vertically). Our original design is back -- but this time using a grid layout.

Changing the Tab Order

Keyboard users press the Tab key to move the focus from widget to widget as they use a form. The order in which the focus moves is called the tab order. Preview multiclip (press Ctrl+T) and try tabbing through the widgets. The tab order may not be what we want so we'll go into tab order mode and change it to the order we want.

When you click the Tab Order toolbar button a number in a blue circle will appear next to every widget that can accept keyboard focus. The numbers represent each widget's tab order, starting from 1. You change the tab order by clicking the widgets in the order you want to be the new tab order. If you make a mistake and need to start again, double click the widget you want to be first, then click the other widgets in the required order as before. When you've finished press Esc to leave tab order mode. If you made a mistake or preferred the previous tab order you can undo your changes by leaving tab order and undoing (press Esc then Ctrl+Z).

Click the Tab Order toolbar button, then click the current clipping Line Edit -- even if it is already number one in the tab order. Next click the previous clipping ListBox, then the auto add clippings CheckBox. Click each button in turn from top (add clipping) to bottom (quit). Press Esc to finish tab order mode, then preview the form and try tabbing through the widgets.

Note that you can stop clicking if the tab order numbers for all the widgets is correct; just press Esc to leave tab order mode.

Setting the Tab Order

Connecting Signals and Slots

Qt provides the signals and slots mechanism for communicating between widgets. Signals are emitted by widgets when particular events occur. We can connect signals to slots, either pre-defined slots or those we create ourselves. In older toolkits this communication would be achieved using callbacks. (For a full explanation of Qt's signals and slots mechanism see the on-line Signals and Slots documentation.)

Connecting Predefined Signals and Slots

Some of an application's functionality can be obtained simply by connecting pre-defined signals and slots. In multiclip there is only one pre-defined connection that we can use, but in the richedit application that we'll build in Creating Main Windows with Actions, Toolbars and Menus we will use many pre-defined signals and slots to get a lot of the functionality we need without having to write any code.

We will connect the Quit button's clicked() signal to the form's accept() slot. The accept() slot notifies the dialog's caller that the dialog is no longer required; since our dialog is our main window this will close the application. Preview the form (press Ctrl+T); click the Quit button. The button works visually but does nothing. Press Esc or close the preview window to leave the preview.

Click the Connect Signals/Slots toolbar button. Click the Quit button, drag to the form and release. The Edit Connections dialog will pop up. The top left hand list box lists the Signals that the widget we've clicked can emit. At the top right is a combobox which lists the form and its widgets; any of these are candidates for receiving signals. Since we released on the form rather than a widget the slots combobox shows the form's name, 'MulticlipForm'. Beneath the combobox is a list box which shows the slots available in the form or widget shown in the combobox. Note that only those slots that can be connected to the highlighted signal are shown. If you clicked a different signal, for example the toggled() toggled() signal, the list of available slots would change. Click the signal, then click the The connection will be shown in the Connections list box. Click OK.

Connecting the clicked() Signal to the accept() Slot

We will make lots of signal/slot connections as we work through the examples, including connections to our own custom slots. Signal/slot connections (using pre-defined signals and slots) work in preview mode. Press Ctrl+T to preview the form; click the form's Quit button. The button now works correctly.

Creating and Connecting Custom Slots

In the first version of Qt Designer you could create the signatures of your custom slots and make the connections, but you could not implement your slots directly. Instead you had to subclass the form and code your slots in the subclass. The subclassing approach is still available, and makes sense in some situations. But now you can implement your slots directly in Qt Designer, so for many dialogs and windows subclassing is no longer necessary. (Qt Designer stores the slot implementations in a .ui.h file; see The ui.h extension approach in The Designer Approach chapter for more about these files.)

The multiclip application requires four slots, one for each button, but only three need to be custom slots since we connected a signal to a pre-defined slot to make the Quit button functional. We need a slot for the Add Clipping button; this will add the current clipping to the list box. The Copy Previous button requires a slot which will copy the selected list box item to the current clipping line edit (and to the clipboard). The Delete Clipping button needs a slot to delete the current clipping and the current list box item. We will also need to write some initialization code so that when the application starts it will put the current clipboard text (if any) into the line edit. The code is written directly in Qt Designer; the snippets are taken from the generated qt/tools/designer/examples/multiclip/multiclip.ui.h file.

We'll need Qt's global clipboard object throughout the code which would mean calling QApplication::clipboard() or qApp->clipboard() in several places. Rather than perform all these function calls we'll keep a pointer to the clipboard in the form itself. Click the Source tab of the Object Explorer. (If the Object Explorer isn't visible click Window|Views|Object Explorer.) The Source tab shows us the functions in our form, the class variables, the forward declarations and the names of the include files we've asked for.

Right click the Class Variables item (near the bottom; you may have to click the scrollbar), then click New on the popup menu. (If there had been any existing variables the popup menu would also have a Delete option.) Type in 'QClipboard *cb;' and press Enter. We will create an init() function in which we will assign this pointer to Qt's global clipboard object. We also need to declare the clipboard header file. Right click Includes (in Declaration), then click New. Type in '<qclipboard.h>' and press Enter. Since we need to refer to the global application object, qApp, we need to add another include declaration. Right click Includes (in Implementation), then click New. Type in '<qapplication.h>' and press Enter. The variable and declarations will be included in the code generated from Qt Designer's .ui file.

We will invoke Qt Designer's code editor and write the code.

We'll create the init() function first. One way of invoking the code editor is to click the Source tab, then click the name of the function you want to work on. If you have no functions or wish to create a new function you need to use the Source tab. Right click the 'protected' item in the Source tab's Slots list, then left click New to launch the Edit Slots dialog. Change the slot's name from 'newSlot' to 'init()' then click OK. You can then click inside the editor window that appears to enter your code.

Note that you are not forced to use Qt Designer's code editor; so long as you add, delete and rename your slots all within Qt Designer, you can edit the implementation code for your slots using a separate external editor and Qt Designer will preserve the code you write.

    void MulticlipForm::init()
    {
        lengthLCDNumber->setBackgroundColor( darkBlue );
        currentLineEdit->setFocus();

        cb = qApp->clipboard();
        connect( cb, SIGNAL( dataChanged() ), SLOT( dataChanged() ) );
        if ( cb->supportsSelection() )
            connect( cb, SIGNAL( selectionChanged() ), SLOT( selectionChanged() ) );

        dataChanged();
    }

The first couple of lines change the LCD number's background color and make the form start with the focus in the line edit. We take a pointer to Qt's global clipboard and keep it in our class variable, cb. We connect the clipboard's dataChanged() signal to a slot called dataChanged(); we will create this slot ourselves shortly. If the clipboard supports selection (under the X Window system for example), we also connect the clipboard's selectionChanged() selectionChanged() signal to a slot of the same name that we will create. Finally we call our dataChanged() dataChanged() slot to populate the line edit with the clipboard's text (if any) when the application begins.

Since we've referred to the dataChanged() and selectionChanged() slots we'll code them next, starting with dataChanged().

    void MulticlipForm::dataChanged()
    {
        QString text;
        text = cb->text();
        clippingChanged( text );
        if ( autoCheckBox->isChecked() )
            addClipping();
    }

We take a copy of the clipboard's text and call our own clippingChanged() slot with the text we've retrieved. If the user has checked the Auto Add Clippings checkbox we call our addClipping() slot to add the clipping to the list box.

The only applicable under the X Window System. Users of MS Windows can still include the code to ensure that the application works multiplatform.

    void MulticlipForm::selectionChanged()
    {
        cb->setSelectionMode( TRUE );
        dataChanged();
        cb->setSelectionMode( FALSE );
    }

We tell the clipboard to use selection mode, we call our dataChanged() dataChanged() slot to retrieve any selected text, then set the clipboard back to its default mode.

In the another custom slot, clippingChanged().

    void MulticlipForm::clippingChanged( const QString & clipping )
    {
        currentLineEdit->setText( clipping );
        lengthLCDNumber->display( (int)clipping.length() );
    }

We set the line edit to whatever text is passed to the clippingChanged() slot and update the LCD number with the length of the new text.

The next slot we'll code will perform the Add Clipping function. This slot is called by our code internally (see the dataChanged() slot above), and when the user clicks the Add Clipping button. Since we want Qt Designer to be able to set up a connection to this slot instead of just typing it in the editor window we'll let Qt Designer create its skeleton for us. Click Edit|Slots to invoke the Edit Slots dialog. Click New Slot and replace the default name of 'new_slot()' with 'addClipping()'. There is no need to change the access specifier or return type. Now that we've created our slot we can implement it in the code editor where it has now appeared.

The Add Clipping button is used to copy the clipping from the Current Clipping line edit into the list box. We also update the length number.

    void MulticlipForm::addClipping()
    {
        QString text = currentLineEdit->text();
        if ( ! text.isEmpty() ) {
            lengthLCDNumber->display( (int)text.length() );
            int i = 0;
            for ( ; i < (int)clippingsListBox->count(); i++ ) {
                if ( clippingsListBox->text( i ) == text ) {
                    i = -1; // Do not add duplicates
                    break;
                }
            }
            if ( i != -1 )
                clippingsListBox->insertItem( text, 0 );
        }
    }

If there is some text we change the LCD's value to the length of the text. We then iterate over all the items in the list box to see if we have the same text already. If the text is not already in the list box we insert it.

To make the Add Clipping button functional we need to connect the button's addClipping() slot. Click the Connect Signals/Slots toolbar button. Click the Add Clipping button, drag to the form and release. (Make sure you drag to the form rather than another widget -- the form will have a thin pink border during the drag. If you make a mistake simply change the name in the Slots combobox.) The Edit Connections dialog will appear. Click the addClipping() slot. Click OK to confirm the connection.

The Copy Previous button is used to copy the selected clipping from the list box into the line edit. The clipping is also placed on the clipboard. The procedure is the same as for the Add Clipping button: first we create the slot, then we implement it and finally we connect to it:

  1. Create the slot.

    Click the Edit|Slots menu item to invoke the Edit Slots dialog. Click New Slot and replace the default 'new_slot()' name with 'copyPrevious()'. Click OK.

  2. Implement the slot.

        void MulticlipForm::copyPrevious()
    {
        if ( clippingsListBox->currentItem() != -1 ) {
            cb->setText( clippingsListBox->currentText() );
            if ( cb->supportsSelection() ) {
                cb->setSelectionMode( TRUE );
                cb->setText( clippingsListBox->currentText() );
                cb->setSelectionMode( FALSE );
            }
        }
    }

    The code for Copy Previous checks to see if there is a selected item in the list box. If there is the item is copied to the line edit. If we are using a system that supports selection we have to repeat the copy, this time with selection mode set. We don't explicitly update the clipboard. When the line edit's text is changed it emits a dataChanged() signal which our dataChanged() slot receives. Our dataChanged() slot updates the clipboard.

  3. Connect to the slot.

    Click the Connect Signals/Slots toolbar button. Click the Copy Previous button, drag to the form and release. The Edit Connections dialog will pop up. Click the clicked() signal and the copyPrevious() slot. Click OK.

We take the same approach to the Delete Clipping button.

  1. Click Edit|Slots to invoke the Edit Slots dialog. Click New Slot and replace the default name with 'deleteClipping()'. Click OK.

  2. The Delete button must delete the current item in the list box and clear the line edit.

        void MulticlipForm::deleteClipping()
    {
        clippingChanged( "" );
        clippingsListBox->removeItem( clippingsListBox->currentItem() );
    }

    We call our own clippingChanged() slot with an empty string and use the list box's removeItem() function to remove the current item.

  3. Connect the Delete Clipping button's clicked() signal to our deleteClipping() slot. (Press F3 -- which is the same as clicking the Connect Signals/Slots toolbar button. Click the Delete Clipping button and drag to the form; release. The Edit Connections dialog will appear. Click the clicked() signal and the deleteClipping() slot. Click OK.)

Compiling and Building an Application

So far we have written about 99% of a Qt application entirely in Qt Designer. To make the application compile and run we must create a main.cpp file from which we can call our form.

The simplest way to create a new source file is by clicking File|New to invoke the 'New File' dialog, then click 'C++ Source' or 'C++ Header' as appropriate, then click OK. A new empty source window will appear. Click File|Save to invoke the Save As dialog, enter 'main.cpp', then click Save.

Enter the following code in the main.cpp C++ editor window:

    #include <qapplication.h>
    #include "multiclip.h"

    int main( int argc, char *argv[] )
    {
        QApplication app( argc, argv );

        MulticlipForm clippingForm;
        app.setMainWidget( &clippingForm );
        clippingForm.show();

        return app.exec();
    }

The program creates a QApplication object and an instance of our MulticlipForm, sets the form to be the main widget and shows the form. The app.exec() call starts off the event loop.

Now start up a console (or xterm), change directory to the multiclip application and run qmake. A Makefile compatible with your system will be generated:

qmake -o Makefile multiclip.pro

You can now make the application, e.g. by running make or nmake. Try compililng and running multiclip. There are many improvement you could make and experimenting with both the layout and the code will help you learn more about Qt and Qt Designer.

This chapter has introduced you to creating multiplatform applications with Qt Designer. We've created a form, populated it with widgets and laid the widgets out neatly and scalably. We've used Qt's signals and slots mechanism to make the application functional and generated the Makefile. These techniques for adding widgets to a form and laying them out with the layout tools; and for creating, coding and connecting slots will be used time and again as you create applications with Qt Designer. The following chapters will present further examples and explore more techniques for using Qt Designer.

[Prev: Preface] [Home] [Next: Creating Main Windows with Actions, Toolbars and Menus]


Qt助手和Qt参考文档

介绍

Qt参考文档介绍

1分钟学会使用Qt助手

更多关于Qt助手

Copyright © 2002 Trolltech Trademarks 译者:SKyPP
Qt 3.0.5版


介绍

本文档介绍了Qt助手，Qt助手是一个提供在线文档的工具。本文档还介绍了Qt参考文档，Qt参考文档可以通过使用Qt助手或网页浏览器方便地浏览。文档分以下几个部分：

  • Qt文档介绍

  • 1分钟学会使用Qt助手

  • 更多关于Qt助手

[Qt助手首页] [下一章：Qt参考文档介绍]

Copyright © 2002 Trolltech Trademarks 译者:SKyPP
Qt 3.0.5版


Qt参考文档介绍

Qt库文档是由开发者们自己写入.cpp文件的。文档组为保证这些文档的正确性和可用性，加以校订，并使文档的质量具有可控性。文档组还撰写了更多的文档，其中有些是描述类及类所涉及的概念，也有些是介绍类的函数和属性。

这些文档关心的是API层，而非核心层。我们尽量使API在不同版本之间得到统一兼容，但是至于核心部分，我们则会不厌其烦地加以改进，使其具备更高的性能和更多的功能。

Qt参考文档由近1,500个HTML文件组成(约2,500多个印张)。它们为Qt类提供了极其丰富的文档。由于开放者们各自有着与众不同的思考和工作方式，我们提供了多种不同归类方式的文档集方便开发者们查阅：

  • 所有的类 列出了Qt公共API中所有的类，共有几百个。

  • 主要的类 列出了您最可能频繁使用的类，篇幅比所有的类要短得多，浏览起来也更为容易。

  • 分组的类 提供了一列组，每列组指向与之对应的类，例如高级窗口部件就是如此。

  • 继承关系 提供了一列类，这些类根据Qt类的从属关系列出。

  • 所有的函数 列出了Qt类的全部函数，每个函数名下则列出了使用它们的类。有些只被一个类用到，有些则被好几个类用到。

你无论在浏览文档的哪个部分，都会发现文档是多方面前后引用的。甚至一小段代码也包含了一些有效链接，所以如果你发现代码里有类的使用，那么类名将是一个指向该类的文档的一个链接。

除一些Qt组件的类文档有详细的说明以外，还有一些概观的文档，对Qt库丰富的外观也做了不少绍；而所有这些文档都可从参考文档首页链接访问到。另外，在$QTDIR/examples中还有不少程序例子。

[上一章：介绍] [Qt助手首页] [下一章：1分钟学会使用Qt助手]

Copyright © 2002 Trolltech Trademarks 译者:SKyPP
Qt 3.0.5版


The 1 Minute Guide to using Qt Assistant

Under Windows, Qt Assistant is available as a menu option on the Qt menu. On Unix, run $QTDIR/bin/assistant from an xterm.

When you start up Qt Assistant, you will be presented with a standard main-window style application, with a menu bar and toolbar. Below these, on the left hand side is a navigation window called the Sidebar, and on the right, taking up most of the space, is the documentation window. By default, the Qt Reference Documentation's home page is shown in the documentation window.

Qt Assistant works in a similar way to a web browser. If you click underlined text (which signifies a cross-reference), the documentation window will present the relevant page. You can bookmark pages of particular interest and you can click the Previous and Next toolbar buttons to navigate within the pages you've visited.

Although Qt Assistant can be used just like a web browser to navigate through the Qt documentation set, Qt Assistant offers a powerful means of navigation that web browsers don't provide. Qt Assistant uses an intelligent algorithm to index all the pages in the documentation sets that it presents so that you can search for particular words and phrases.

To perform a search, click the Index tab on the Sidebar (or click Ctrl+I). In the 'Look For' line edit enter a word, e.g. 'homedirpath'. As you type, words are found and highlighted in a list beneath the line edit. If the highlighted text matches what you're looking for, double click it, (or press Enter) and the documentation window will display the relevant page. You rarely have to type in the whole word before Qt Assistant finds a match.

For some words there may be more than one possible page that is relevant. For example, enter 'setenabled' in the 'Look For' line edit. As you type, words are found and highlighted in the list beneath the line edit, as before. Once the highlighted text matches what you're looking for, double click it, (or press Enter). In the case of setEnabled, it is a function name which occurs in several classes, so a dialog pops up listing the possible choices. Click the choice you're interested in (or move to it using the Up and Down arrow keys and press Enter). The relevant page will display in the documentation window.

[Prev: Introduction to the Qt Reference Documentation] [Home] [Next: Qt Assistant in More Detail]


Qt Assistant in More Detail

The Sidebar

The sidebar provides three ways of navigating documentation:

  1. The Contents tab presents a tree view of the documentation sets that are available. If you click an item, its documentation will appear in the documentation window. If you double click an item or click a '+' sign to the left of an item, the item's sub-items will appear. Click a sub-item to make its page appear in the documentation window. Click a '-' sign to the left of an item to hide its sub-items.

  2. The Index tab is used to look up key words or phrases. See The 1 Minute Guide to using Qt Assistant for how to use this tab.

  3. The Bookmarks tab lists any bookmarks you've made. Double click a bookmark to make its page appear in the documentation window. The Bookmarks tab has a New Bookmark button and a Delete Bookmark button at the bottom. Click New Bookmark to bookmark the page that is showing in the documentation window. Click a bookmark in the list, then click Delete Bookmark to delete the highlighted bookmark.

If you want the documentation window to use as much space as possible, you can easily hide or show the Sidebar. If the Sidebar is showing, press Ctrl+T, Ctrl+I or Ctrl+B to hide it. If the Sidebar is hidden, press Ctrl+T to show it on the Contents tab, or press Ctrl+I to show it on the Index tab (with the focus in the 'Look For' line edit box), or press Ctrl+B to show it on the Bookmarks tab.

The Sidebar is a dock window, so you can drag it to the top, left, right or bottom of Qt Assistant's window, or you can drag it outside Qt Assistant to float it.

The Toolbar

The toolbar provides fast access to the most common actions.

  • Previous takes you to the previous page. The menu option is Go|Previous and the keyboard shortcut is Alt+Left Arrow.

  • Next takes you to the next page. The menu option is Go|Next and the keyboard shortcut is Alt+Right Arrow.

  • Home takes you to the home page (normally the home page of the Qt Reference Documentation). The menu option is Go|Home and the keyboard shortcut is Ctrl+Home.

  • Copy copies any selected text to the clipboard. The menu option is Edit|Copy and the keyboard shortcut is Ctrl+C.

  • Find in Text invokes the Find Text dialog. The menu option is Edit|Find in Text and the keyboard shortcut is Ctrl+F.

  • Print invokes the Print dialog. The menu option is File|Print and the keyboard shortcut is Ctrl+P.

  • Zoom in increases the font size. The menu option is View|Zoom in and the keyboard shortcut is Ctrl++.

  • Zoom out decreases the font size. The menu option is View|Zoom out and the keyboard shortcut is Ctrl+-.

The remaining toolbar buttons are bookmarks and will vary depending on your configuration.

The Menus

The File Menu

  • File|Print invokes the Print dialog.

  • File|Exit terminates Qt Assistant.

The Edit Menu

  • Edit|Copy copies any selected text to the clipboard.

  • Edit|Find in Text invokes the Find Text dialog.

  • Edit|Settings invokes the Settings dialog.

The View Menu

  • View|Zoom in increases the font size.

  • View|Zoom out decreases the font size.

  • View|Views|Sidebar toggles the display of the Sidebar.

  • View|Views|Toolbar toggles the display of the Toolbar.

  • View|Views|Line up lines up the toolbar buttons in the Toolbar.

The Go Menu

  • Go|Previous display the previous page.

  • Go|Next display the next page.

  • Go|home go to the home page.

This menu also has additional items; these are pre-defined bookmarks that vary depending on your configuration.

The Bookmarks Menu

  • Bookmarks|Add add the current page to the list of bookmarks.

This menu may have additional items, i.e. any bookmarks that you have already made. If you want to delete a bookmark go to the Bookmarks tab on the Sidebar.

The Dialogs

The Print Dialog

This dialog is platform-specific. It gives access to various printer options and can be used to print the current page.

The Find Text Dialog

This dialog is used to find text in the current page. Enter the text you want to find in the Find line edit. If you check the 'Whole words only' checkbox, the search will only consider whole words, i.e. if you search for 'spin' with this checkbox checked it will not match 'spinbox', but will match 'spin'. If you check the 'Case sensitive' check box then, for example, 'spin' will match 'spin' but not 'Spin'. You can search Forward or Backward from your current position in the page by clicking one of the Direction radio buttons. Click the Find button to search (or search again), and click the Close button to finish.

The Settings Dialog

This dialog is used to set your preferences for Qt Assistant. You can change the base font used throughout by choosing a new font from the Font combobox. You can choose a new fixed-width font, e.g. used to show code snippets, by choosing a new font from the 'Fixed font' combobox. You can change the color of hypertext links by clicking the 'Link color' color button. Uncheck the 'Underline links' checkbox if you don't want underlined links. Click OK to confirm your changes or click Cancel to keep the previous settings.

Qt Assistant will remember your settings between sessions, including window sizes and positions, and which page(s) you have open.


Standard Accelerator Keys

Applications invariably need to define accelerator keys for actions. Qt fully supports accelerators, for example with QAccel::shortcutKey().

Here are Microsoft's recommendations for accelerator keys, with comments about the Open Group's recommendations where they exist and differ. For most commands, the Open Group either has no advice or agrees with Microsoft.

The emboldened letter plus Alt is Microsoft's recommended choice, and we recommend supporting it. For an Apply button, for example, we recommend QButton::setText( tr("&Apply") );

If you have conflicting commands (e.g. About and Apply buttons in the same dialog), you must decide for yourself.

  • About
  • Always on Top
  • Apply
  • Back
  • Browse
  • Close (CDE: Alt+F4; Alt+F4 is "close window" in Windows)
  • Copy (CDE: Ctrl+C, Ctrl+Insert)
  • Copy Here
  • Create Shortcut
  • Create Shortcut Here
  • Cut
  • Delete
  • Edit
  • Exit
  • Explore
  • File
  • Find
  • Help
  • Help Topics
  • Hide
  • Insert
  • Insert Object
  • Link Here
  • Maximize
  • Minimize
  • Move
  • Move Here
  • New
  • Next
  • No
  • Open
  • Open With
  • Page Setup
  • Paste
  • Paste Link
  • Paste Shortcut
  • Paste Special
  • Pause
  • Play
  • Print
  • Print Here
  • Properties
  • Quick View
  • Redo (CDE: Ctrl+Y, Alt+Backspace)
  • Repeat
  • Restore
  • Resume
  • Retry
  • Run
  • Save
  • Save As
  • Select All
  • Send To
  • Show
  • Size
  • Split
  • Stop
  • Undo (CDE: Ctrl+Z or Alt+Backspace)
  • View
  • What's This?
  • Window
  • Yes

There are also a lot of other keys and actions (that use other modifier keys than Alt). See the Microsoft and The Open Group documentation for details.

The Microsoft book has ISBN 0735605661. The corresponding Open Group book is very hard to find, rather expensive and we cannot recommend it. However, if you really want it, OGPubs@opengroup.org might be able to help. Ask them for ISBN 1859121047.


Thanks!

The following (and probably many others) have provided bug reports, suggestions, patches, beta testing, or done us other favors. We thank you all:

Adam P. Jenkins <ajenkins at cs.umass.edu>
Ahmed Metwally <ametwaly at auc-cs28.eun.eg>
Aidas Kasparas <kaspar at soften.ktu.lt>
Alejandro Aguilar Sierra <asierra at servidor.unam.mx>
Alex <steeper at dial.pipex.com>
Alex Kambis <kambis at eos913c.gsfc.nasa.gov>
Alexander Kozlov <alex at hale.appl.sci-nnov.ru>
Alexander Sanda <alex at darkstar.ping.at>
Amos Leffler <leffler at netaxs.com>
Anders Hanson <andhan at lls.se>
Andreas Schlempp <schlempp at egd.igd.fhg.de>
Andrew Bell <abell at vsys.com>
Andrew Gillham <gillhaa at ghost.whirlpool.com>
Andrew J. Robinson <robinson at eclipse.net>
Andrew Pavlomanolakos <app at novanet.net.au>
Andrew R. Tefft <teffta at crypt.erie.ge.com>
Andrew Vajoczki <vajoczki at interlog.com>
André Johansen <Andre.Johansen at funcom.no>
Andy Shaw <andy at east.no>
Andy Brice <andyb at suntail.net>
Anton Keyter <ant at intekom.co.za>
Arnt Gulbrandsen <arnt at gulbrandsen.priv.no>
Ashley Winters <jql at accessone.com>
Aubrey Soper <azdak at ix.netcom.com>
Axel Schwenke <schwenke at HTWM.DE>
Ben Bergen <ben at gmg.com>
Bernard Leach <B.Leach at compsoc.cs.latrobe.edu.au>
Bernd Johannes Wuebben <wuebben at math.cornell.edu>
Bernd S. Brentrup <bsb at uni-muenster.de>
Bert Haverkamp <b.r.j.haverkamp at et.tudelft.nl>
Bjorn Reese <breese at dit.ou.dk>
Brian Beattie <beattie at drcpdx.stt3.com>
Brian P. Theodore <theodore at std.saic.com>
Brian White <bcwhite at verisim.com>
Bryan Scattergood <bryan at fsel.com>
Carsten Steckel <carsten at cs.newcastle.edu.au>
Chao-Hsin, Lin <linchao at charlie.cns.iit.edu>
Chip Salzenberg <chip at atlantic.net>
Chris Zwilling <crzwlng at cloudnet.com>
Christian Czezatke <e9025461 at student.tuwien.ac.at>
Christopher Andrew Spiking <cas at Cs.Nott.AC.UK>
Christopher J. White <cjwhite at rgit.wustl.edu>
Claus Werner <lzu96cw at reading.ac.uk>
Cloyce D. Spradling <cloyce at austin.ibm.com>
Colin Paul Adams <colin at colina.demon.co.uk>
Cristiano Verondini <cverond at deis219.deis.unibo.it>
Damyan Pepper <damyanp at cogs.susx.ac.uk>
Dan Nickerson <nickersond at uthscsa.edu>
Daniel Brahneborg <basic at well.com>
Daniel Gruner <dgruner at tikva.chem.utoronto.ca>
Daniel J Mitchell <dan at rebellion.co.uk>
Danilo Fiorenzano <danilo at terranet.ab.ca>
Dante Profeta <profeta at neomedia.it>
Darryl Ruggles <001654r at dragon.acadiau.ca>
Dave <dave at stellacore.com>
Dave Steffen <steffend at glitch.physics.colostate.edu>
Dean Hall <dwhall at deskstation.com>
Denis Y. Pershin <dyp at isis.nsu.ru>
Diedrich Vorberg <Diedrich_Vorberg at cp.prima.ruhr.de>
Dietmar Schaefer <dietmar at cs.newcastle.edu.au>
Dimitri Papadopoulos <dpo at club-internet.fr>
Dirk Mueller <mueller at kde.org>
Dirk Schwartmann <dirk.schwartmann at dlr.de>
Dominik Jergus <djergus at ics.uci.edu>
Don Sanders <sanders at kde.org>
Donald A. Seielstad <donald at gromit.scs.uiuc.edu>
Donna J. Armijo <donna at KachinaTech.COM>
Doug Boreland <dborel at amex-trs.com>
Douglas Lenz <dlenz at spedsoft.com>
Dr Mek Buhl Nielsen <m.b.nielsen at bham.ac.uk>
Dr Willem A. Schreuder <Willem.Schreuder at prinmath.com>
E. Kevin Hall <hall at boston.sgi.com>
Ed Mackey <emackey at Early.com>
Edmund Taylor <etaylor at interaccess.com>
Eric Bos <Eric.Bos at adelaide.maptek.com.au>
Eric Brunson <brunson at brunson.com>
Eric Jansen <jansen at photon.com>
Erik Norell <erik at Astrakan.HGS.SE>
Erik Thiele <erik at unterland.de>
Ernie Pasveer <erniep at vsl.com>
FRBall <frb at umr.edu>
FUJIMOTO Koji <kochan at mbox.kyoto-inet.or.jp>
Fergal Mc Carthy <fergal at ilo.dec.com>
Frank Gockel <gockel at etecs4.uni-duisburg.de>
Frank Roscher <frank at chemnitz.abs-rz.de>
Fredrik Markström <fredrik at zod.campus.luth.se>
Fredrik Nehr <fredrik_nehr at ivab.se>
FrenzelBhv at aol.com
Frugal <frugal at wardrobe.demon.co.uk>
Frugal the Curious <Chris.Ward at softcare.co.uk>
Gabor V. Gulyas <gabor at robiomat.com>
Gary E. Sherman <sherman at mrcc.com>
Geoff Carpenter <GCC at watson.ibm.com>
Geoffrey Higginson <ghiggins at gulf.uvic.ca>
Georg Filios <Georg.Filios at post.rwth-aachen.de>
George Simunovich <george at cia-g.com>
Giovanni Carapelli <gcarapel at mbox.vol.it>
Greg Tomalesky <tomalesk at yrkpa.kias.com>
Gregg Jensen <gwj at stl.nexen.com>
Gustav "Gurre" Kalvesten <a94guska at ida.his.se>
Hal DeVore <hdevore at crow.bmc.com>
Hans Flaechsig <hans at hannes.owl.de>
Hans Schlenker <schlenkh at informatik.uni-muenchen.de>
Hardo Mueller <hardo at ipb.uni-bonn.de>
Henty Waker <henty at foxbat.sur.uct.ac.za>
Hrafnkell Eiriksson <hkelle at mmedia.is>
Ildefonso Junquero Martin-Arroyo <junquero at sainsel.es>
Ingo Stapel <ingo.stapel at tu-clausthal.de>
J. Solomon Kostelnik <roz at one.net>
Jae Cho <cs184-dc at ute.CS.Berkeley.EDU>
James McIninch <james at amber.biology.gatech.edu>
Jan Aarsaether <jaa at metis.no>
Jaromir Dolecek <dolecek at ics.muni.cz>
Jason Evans <evans911 at cs.uidaho.edu>
Jay Painter <jay at a42.com>
Jean-Philippe Langlois <jpl at iname.com>
Jeff Harris <jharris at cis.ohio-state.edu>
Jeff Largent <jlargent at iu.net>
Jeffrey Vetter <vetter at lanl.gov>
Jeremy Wohl <jeremy at godzilli.cs.sunysb.edu>
Jim Lauchlan <jim.lauchlan at gecm.com>
Joachim Backes <backes at rhrk.uni-kl.de>
Jochen Scharrlach <jscharrl at BA-Stuttgart.De>
Joe Croft <jcroft at swbell.net>
Joel Lindholm <wizball at kewl.campus.luth.se>
John H. Reppy <jhr at research.att.com>
John Huertas - Jourda <octarine at gte.net>
John Ouellette <ouellet at beluga.phys.UVic.CA>
John Vidar Larring <larring at weatherone.tv>
Jon Brumfitt <jbrumfit at astro.estec.esa.nl>
Jose Castro <jocastro at erols.com>
Julian Enticknap <Julian.Enticknap at UK.Sun.COM>
Jussi-Pekka Sairanen <jussi-pekka.sairanen at research.nokia.com>
Kalle Dalheimer <kalle at dalheimer.hh.eunet.de>
Karl Robillard <karl at skygames.com>
Keith Brown <ksbrown at ix.netcom.com>
Keith Dowsett <kdowsett at rpms.ac.uk>
Ken Hollis <khollis at northwest.com>
Kirill Konyagin <kirill at asplinux.ru>
Klaus Ebner <klaus at gaspode.ndh.com>
Klaus-Georg Adams <Klaus-Georg.Adams at chemie.uni-karlsruhe.de>
Kristof Depraetere <Kristof.Depraetere at rug.ac.be>
Kurt L Anderson <kurt+ at osu.edu>
Larry Lee <lclee at primenet.com>
Lars Knoll <knoll at mpi-hd.mpg.de>
M. G. Berberich <berberic at fmi.uni-passau.de>
Maas-Maarten Zeeman <mzeeman at cs.vu.nl>
Magnus Persson <mpersson at eritel.se>
Mario Weilguni <mweilguni at arctica.sime.com>
Mariya <muha at iclub.nsu.ru>
Mark Summerfield <summer at perlpress.com>
Markku Hihnala <mah at ee.oulu.fi>
Marko Macek <Marko.Macek at snet.fer.uni-lj.si>
Martin Baehr <mbaehr at email.archlab.tuwien.ac.at>
Martin Mueller <mm at lunetix.de>
Martin van Velsen <vvelsen at ronix.ptf.hro.nl>
Matthias Ettrich <ettrich at fisher.informatik.uni-tuebingen.de>
Matthias Suencksen <msuencks at techfak.uni-bielefeld.de>
Mattias Engdegård <f91-men at nada.kth.se>
Michael Figley <figley at ibmoto.com>
Michael George <george at quark.im4u.net>
Michael Graff <explorer at flame.org>
Michael H. Price II <price at ERC.MsState.Edu>
Michael Harnois <mharnois at sbt.net>
Michael Hohmuth <hohmuth at inf.tu-dresden.de>
Michael Leodolter <michael at lab1.psy.univie.ac.at>
Michael Roth <mroth at nessie.de>
Michael Schwendt <Michael_Schwendt at public.uni-hamburg.de>
Michal Polak <mpolak at fi.muni.cz>
Mikael Bourges-Sevenier <bourges at int-evry.fr>
Mike Fearn <hp003 at dra.hmg.gb>
Mike Perik <mikep at crt.com>
Mike Sharkey <msharkey at softarc.com>
Miroslav Flidr <flidr at kky.zcu.cz>
Miyata Shigeru <miyata at kusm.kyoto-u.ac.jp>
Myron Uecker <muecker at csd.net>
NGOk YUK YAU <zzy at compuserve.com>
Neal Sanche <neal at nsdev.org>
Niclas Anderberg <agony at sparta.lu.se>
Oliver Eiden <o.eiden at pop.ruhr.de>
Oliver Elphick <olly at lfix.co.uk>
Olivier Verloove <overloov at ulb.ac.be>
Osku Salerma <osku at iki.fi>
P. J. Leonard <eespjl at ee.bath.ac.uk>
Paolo Galatola <paolo at iris.polito.it>
Pat Dowler <dowler at pt1B1106.FSH.UVic.CA>
Patrice TROGNON <trognon at apogee-com.fr>
Patrick Voigt <Patrick.Voigt at Informatik.TU-Chemnitz.DE>
Paul Bucheit <ptb at k2.cwru.edu>
Paul Kendall <paul at kcbbs.gen.nz>
Paul Marquis <pmarquis at iddptm.iddis.com>
Peter Bender <bender at iib.bauwesen.th-darmstadt.de>
Peter Klotz <p.klotz at icoserve.com>
Peter Pletcher <peter at delilah>
Pierre Rocque <rocque at CRHSC.Umontreal.CA>
Pohorecki Wladyslaw <POHORECKI at novell.ftj.agh.edu.pl>
R.S. MALLOZZI, ES-84, 205-544-0887 <MALLOZZI at bowie.msfc.nasa.gov>
ROHLFS Reiner <Reiner.Rohlfs at obs.unige.ch>
Ralf Stanke <ralf at mcshh.hanse.de>
Reggie Stadlbauer <reggie at kde.org>
Richard D. Jackson <rjackson at bga.com>
Richard Keech <rkeech at colesmyer.com.au>
Richard Moore <moorer at cs.man.ac.uk>
Rick Brohl <rbrohl at uswest.com>
Robert Anderson <Robert.E.Anderson at unh.edu>
Robert Cimrman <cimrman at marius.univ-mrs.fr>
Roberto Alsina <ralsina at ultra7.unl.edu.ar>
Salman Sheikh <salman at vdragon.gsfc.nasa.gov>
Sandro Sigala <ssigala at globalnet.it>
Scott Coppen <scoppen at emerald.tufts.edu>
Sean Vyain <svyain at mail.tds.net>
Sirtaj Singh Kang <ssk at physics.unimelb.EDU.AU>
Sivan Toledo
Stefan Cronert <d93-scr at nada.kth.se>
Stefan Taferner <taf at porsche.co.at>
Steffen Hansen <stefh at dit.ou.dk>
Stephan Pfab <pfab at mathematik.uni-ulm.de>
Stephane Zermatten <szermat at ibm.net>
Sven Fischer <sven at comnets.rwth-aachen.de>
Sven Riedel <lynx at heim8.tu-clausthal.de>
Terje Dalen <terje at norcontrol.no>
Thomas Lineal <thomas at ricci.allcon.com>
Thomas Rath <rath at mac-info-link.de>
Thorsten Ende <the at is-bremen.de>
Tiaan Wessels <tiaan at inetsys.alt.za>
Tim D. Gilman <tdgilman at best.com>
Tom Houlder <thoulder at icor.fr>
Tony Albrecht <Tony.Albrecht at adelaide.maptek.com.au>
Torgeir Hovden <hovden at akkurat.idt.ntnu.no>
Trond Hellem Bø <s638 at ii.uib.no>
Trond Solli <Trond.Solli at marintek.sintef.no>
Ulf Stelbe <ust at egd.igd.fhg.de>
Ulrich Hertlein <uhe at cs.tu-berlin.de>
Ulrich Ring <ur at daveg.com>
Uwe Thiem <uwe at uwix.alt.na>
Vadim Zaliva <lord at crocodile.org>
Val Gough <val at stellacore.com>
Vilhelm Sjöberg <ville at swipnet.se>
Vlad Karpinsky <vlad at crocodile.org>
Volker Poplawski <volkerp at stepnet.de>
Warwick Allison <warwick at it.uq.edu.au>
Xiaojian Li <lixj at monte.rutgers.edu>
Ximenes <ximenes at netset.com>
Y. N. Lo <ynlo at netcom.ca>
Zyklon <zyk at dds.nl>
atsushi konno <jibe at ppp.bekkoame.or.jp>
berry at hxi.com
boris passek <boris at ice.fb12.TU-Berlin.DE>
fidaire <fidaire at bip.fr>
joeh at sugar-river.net
rinsch at aea.ruhr-uni-bochum.de
tsutsui at kekvax.kek.jp
vandevod at cs.rpi.edu
vinckeg at sebb.bel.alcatel.be
yleffler at ucis.vill.edu

We hope there are not too many omissions from the list. Any omissions are bugs and should be reported to qt-bugs@trolltech.com like other bugs in the Qt code or documentation.


如何报告bug

如果你认为你发现了Qt中的bug，我们很高兴听到这些，这样我们就可以修复它了。

在报告bug之前，请检查我们网站上的FAQ和平台注释，查看一下这个问题是否已经知道。

在你的bug报告中通常应该包含以下信息：

  1. 你的编译器的名称和版本
  2. 你的操作系统的名称和版本
  3. 你所使用的Qt的版本和你在编译时使用的配置选项。

如果你报告的问题只是在运行时可见的，请试着建立一个小的测试程序来显示运行时发生的问题。通常情况下，qt/examples目录下有很多示例程序，你只要对其中一个进行一些小的修改就可以了。

请把bug报告寄到qt-bugs@trolltech.com。

Copyright © 2002 Trolltech Trademarks 译者:Cavendish
Qt 3.0.5版


抽象窗口部件类

这些类是抽象窗口部件，它们自己通常是不可用的，但是它们提供了很多它们的子类可以使用的功能。

QButton | 按钮窗口部件的抽象基类，提供了按钮所共有的功能
QCanvas | 可以包含QCanvasItem对象的二维区域
QDialog | 对话窗口的基类
QFrame | 有框架的窗口部件的基类
QGridView | 固定大小栅格的抽象基类
QScrollView | 带有滚动条需要的滚动区域
QWidget | 所有用户界面对象的基类
QWizard | 向导对话框的构架

Copyright © 2002 Trolltech Trademarks 译者:Cavendish
Qt 3.0.5版


Analog Clock

This example displays an analog clock widget.

Header file:

/****************************************************************************
** $Id:  qt/aclock.h   3.0.5   edited Oct 12 2001 $
**
** Copyright (C) 1992-2000 Trolltech AS.  All rights reserved.
**
** This file is part of an example program for Qt.  This example
** program may be used, distributed and modified without limitation.
**
*****************************************************************************/

#ifndef ACLOCK_H
#define ACLOCK_H

#include <qwidget.h>
#include <qdatetime.h>

class AnalogClock : public QWidget              // analog clock widget
{
    Q_OBJECT
public:
    AnalogClock( QWidget *parent=0, const char *name=0 );
    void setAutoMask(bool b);

public slots:
    void setTime( const QTime & t );

protected:
    void updateMask();
    void paintEvent( QPaintEvent *);
    void mousePressEvent( QMouseEvent *);
    void mouseMoveEvent( QMouseEvent *);

private slots:
    void drawClock( QPainter* );
    void        timeout();

private:
    QPoint clickPos;
    QTime       time;
};

#endif // ACLOCK_H

Implementation:

/****************************************************************************
** $Id:  qt/aclock.cpp   3.0.5   edited Oct 12 2001 $
**
** Copyright (C) 1992-2000 Trolltech AS.  All rights reserved.
**
** This file is part of an example program for Qt.  This example
** program may be used, distributed and modified without limitation.
**
*****************************************************************************/

#include "aclock.h"
#include <qtimer.h>
#include <qpainter.h>
#include <qbitmap.h>

//
// Constructs an analog clock widget that uses an internal QTimer.
//

AnalogClock::AnalogClock( QWidget *parent, const char *name )
    : QWidget( parent, name )
{
    time = QTime::currentTime();                // get current time
    QTimer *internalTimer = new QTimer( this ); // create internal timer
    connect( internalTimer, SIGNAL(timeout()), SLOT(timeout()) );
    internalTimer->start( 5000 );               // emit signal every 5 seconds
}

void AnalogClock::mousePressEvent( QMouseEvent *e )
{
    if(isTopLevel())
        clickPos = e->pos() + QPoint(geometry().topLeft() - frameGeometry().topLeft());
}

void AnalogClock::mouseMoveEvent( QMouseEvent *e )
{
    if(isTopLevel())
        move( e->globalPos() - clickPos );
}

void AnalogClock::setTime( const QTime & t )
{
    time = t;
    timeout();
}

//
// The QTimer::timeout() signal is received by this slot.
//

void AnalogClock::timeout()
{
    QTime new_time = QTime::currentTime();      // get the current time
    time = time.addSecs( 5 );
    if ( new_time.minute() != time.minute() ) { // minute has changed
        if (autoMask())
            updateMask();
        else
            update();
    }
}

void AnalogClock::paintEvent( QPaintEvent * )
{
    if ( autoMask() )
        return;
    QPainter paint( this );
    paint.setBrush( colorGroup().foreground() );
    drawClock( &paint );
}

// If the clock is transparent, we use updateMask()
// instead of paintEvent()

void AnalogClock::updateMask()  // paint clock mask
{
    QBitmap bm( size() );
    bm.fill( color0 );                  //transparent

    QPainter paint;
    paint.begin( &bm, this );
    paint.setBrush( color1 );           // use non-transparent color
    paint.setPen( color1 );

    drawClock( &paint );

    paint.end();
    setMask( bm );
}

//
// The clock is painted using a 1000x1000 square coordinate system, in
// the a centered square, as big as possible.  The painter's pen and
// brush colors are used.
//
void AnalogClock::drawClock( QPainter *paint )
{
    paint->save();

    paint->setWindow( -500,-500, 1000,1000 );

    QRect v = paint->viewport();
    int d = QMIN( v.width(), v.height() );
    paint->setViewport( v.left() + (v.width()-d)/2,
                        v.top() + (v.height()-d)/2, d, d );

    // time = QTime::currentTime();
    QPointArray pts;

    paint->save();
    paint->rotate( 30*(time.hour()%12-3) + time.minute()/2 );
    pts.setPoints( 4, -20,0,  0,-20, 300,0, 0,20 );
    paint->drawConvexPolygon( pts );
    paint->restore();

    paint->save();
    paint->rotate( (time.minute()-15)*6 );
    pts.setPoints( 4, -10,0, 0,-10, 400,0, 0,10 );
    paint->drawConvexPolygon( pts );
    paint->restore();

    for ( int i=0; i<12; i++ ) {
        paint->drawLine( 440,0, 460,0 );
        paint->rotate( 30 );
    }

    paint->restore();
}

void AnalogClock::setAutoMask(bool b)
{
    if (b)
        setBackgroundMode( PaletteForeground );
    else
        setBackgroundMode( PaletteBackground );
    QWidget::setAutoMask(b);
}

Main:

/****************************************************************************
** $Id:  qt/main.cpp   3.0.5   edited Oct 12 2001 $
**
** Copyright (C) 1992-2000 Trolltech AS.  All rights reserved.
**
** This file is part of an example program for Qt.  This example
** program may be used, distributed and modified without limitation.
**
*****************************************************************************/

#include "aclock.h"
#include <qapplication.h>

int main( int argc, char **argv )
{
    QApplication a( argc, argv );
    AnalogClock *clock = new AnalogClock;
    if ( argc == 2 && strcmp( argv[1], "-transparent" ) == 0 )
        clock->setAutoMask( TRUE );
    clock->resize( 100, 100 );
    a.setMainWidget( clock );
    clock->setCaption("Qt Example - Analog Clock");
    clock->show();
    int result = a.exec();
    delete clock;
    return result;
}

See also Examples.


Walkthrough: A Tiny Editor Illustrating QActionGroup

In the following we will step through a very rudimental editor program that shows one of the most common uses of the QActionGroup class: how to combine several toggle actions in a way that allows one-of-many choices.

If you're not yet familiar with the concept of actions, please refer to the Simple Application Walkthrough featuring QAction.

A tiny main program

    #include <qapplication.h>
    #include "editor.h"

    int main( int argc, char ** argv)
    {
        QApplication app( argc, argv );
        Editor editor;
        editor.setCaption( "Qt Example - Actiongroup" );
        app.setMainWidget( &editor );
        editor.show();
        return app.exec();
    }

This tiny editor is a very small program. It might be unusual for an editor but it does not even provide the possibility to open a file given as a commandline argument. The reason for this is simple: It has nothing to to with QActionGroups.

The crucial point in the above main() is that we make editor, an object constructed from a self-written class Editor, the main widget in our application. This class is defined in editor.h.

When you read through the code and happen to be unsure about something: The Simple Application Walkthrough explains the elements of a typical Qt main program in detail.

The interface of the Editor class

Before implementing the Editor class we should think about what it is supposed to do. Fortunately Qt provides a full-featured rich text editor class, QTextEdit. The only thing left for us is to give it a user interface.

    #include <qmainwindow.h>
    class QTextEdit;
    class QAction;

    class Editor : public QMainWindow
    {
        Q_OBJECT

    public:
        Editor();

    private slots:
        void setFontColor( QAction * );

    private:
        QTextEdit * editor;
        QAction * setRedFont;
    };

As we look for a means to implement one-of-many choices, a nice example would involve two buttons that make the user change the font color: If he or she invokes the setRedFont action the font color changes from default black to red.

To do this color change we need a slot, setFontColor() that takes care about the signal the action emits.

The Editor class itself is derived from QMainWindow. Only the constructor might be called from outside the class.

Action!

    #include "editor.h"

    #include <qtextedit.h>
    #include <qmenubar.h>
    #include <qpopupmenu.h>
    #include <qtoolbar.h>
    #include <qaction.h>

It's not that much that we need for our tiny editor: QTextEdit, QMenuBar, QToolBar, QPopupMenu and last but not least QAction and QActionGroup from qaction.h.

    Editor::Editor()
        : QMainWindow( 0, "main window")
    {
        QActionGroup * colors = new QActionGroup( this, "colors", TRUE );

If one of the buttons is on, the other one must be off. The easiest way to to this is to create an action group, colors, that controls this exclusive behaviour. This is done by setting the third argument of the QActionGroup constructor to TRUE (we could omit it because it's the default). As simple as this we get an exclusive action group that will look after its member actions and switch off all other toggle actions except the one that is on.

        QAction * setBlackFont = new QAction( "black", QPixmap( (const char**)black_xpm ),
                                              "Font color: black", CTRL+Key_B,
                                              colors, "blackfontcolor", TRUE );

Then we create our first action, the one that sets the font color back to default black. It is called setBlackFont and is equipped with a descriptive QAction::text() reading black, a QAction::menuText() reading Font color: black, a QAction::iconSet() derived from the pixmap black_xpm and ALT+B as keyboard accelerator.

The last argument of the action constructor, TRUE, is responsible for making setBlackFont a toggle action that can be switched on or off. Most importantly setBlackFont becomes a member of the colors action group at creation time: colors is defined to be its parent.

        setRedFont = new QAction( "red", QPixmap( (const char**)red_xpm ), "Font color: red",
                                  CTRL+Key_R, colors, "redfontcolor", TRUE );

The same way we create the other toggle action, setRedFont, as a child of colors.

Whenever one of the two members of the colors group emits the QAction::toggled() signal the QActionGroup is notified internally and emits the QActionGroup::selected() signal in turn. QActionGroup::selected() carries the action that caused the signal as its argument.

All we have to do now is to connect this signal to a slot that changes the font color to red or black depending on the toggled action:

        QObject::connect( colors, SIGNAL( selected( QAction * ) ),
                          this, SLOT( setFontColor( QAction * ) ) );

This is the entire trick. Thus let's recall what we have done so far: We created two toggle actions, setRedFont and setBlackFont. Because they are children of an exclusive QActionGroup named colors it is impossible for the user to type red and black at the same time: Whenever he or she invokes one of the actions the other one changes state to off, colors emits a QActionGroup::selected() signal and the setFontColor() slot takes care of it.

All we have to do now is to add our two actions to the Editor window.

        QToolBar * toolbar = new QToolBar( this, "toolbar" );

First we create a tool bar.

        colors->addTo( toolbar );

But instead of adding each action manually we simply add their parent action group to toolbar and are done. colors makes sure that setBlackFont and setRedFont find themselves presented in the tool bar: setBlackFont as a tool button decorated with the black_xpm pixmap on the left, setRedFont (because it was added to colors later) to its right.

        QPopupMenu * font = new QPopupMenu( this );
        menuBar()->insertItem( "&Font", font );

Next we create a popup menu and insert it into the menu bar under the Font entry.

In a menu with this name a user would certainly expect to find more than just two entries to change the font color. You might want to add other font related actions in the future, and therefore it would be nice to group setBlackFont and setRedFont in a submenu entirely dedicated to the purpose of changing font colors.

With an action group this is easy. We simply tell colors to group together all of its members in a single submenu:

        colors->setUsesDropDown( TRUE );

This however causes a problem: a submenu entry must have a menu text, and up to now we don't have any.

When we recall that action groups intrinsically are QActions themselves the solution becomes obvious:

        colors->setMenuText( "Font Color" );

We simply assign the menu text Font Color to colors.

The rest is business as usual:

        colors->addTo( font );

We add the new and improved QActionGroup as a submenu to the font popup menu.

        editor = new QTextEdit( this, "editor" );

Last but not least we create the heart of Editor, the rich text editor ...

        setCentralWidget( editor );

... and make it the central widget in our window.

    }

The only thing left to implement is the setFontColor slot that is responsible for changing the font color to red or black depending on which action was toggled on.

    void Editor::setFontColor( QAction * coloraction )
    {

As the QActionGroup::selected() signal carries the relevant action as its argument, the first thing we have to do is to preserve it in the coloraction variable for later use.

        if ( coloraction == setRedFont )
            editor->setColor( red );

If coloraction is the same as setRedFont we change the editor's font color to red.

        else
            editor->setColor( black );

Otherwise it is set to black.

    }

See also Step-by-step Examples.


A Tiny Example Featuring QActionGroup

This example program shows how to use an exclusive action group.

Detailed explanations of the code can be found in the walkthrough.

Main:

/*
$Id$
*/

#include <qapplication.h>

#include "editor.h"

int main( int argc, char ** argv)
{
    QApplication app( argc, argv );
    Editor editor;
    editor.setCaption( "Qt Example - Actiongroup" );
    app.setMainWidget( &editor );
    editor.show();
    return app.exec();
}

Header file:

/*
$Id$
*/

#ifndef EDITOR_H
#define EDITOR_H

#include <qmainwindow.h>

class QTextEdit;
class QAction;

class Editor : public QMainWindow
{
    Q_OBJECT

public:
    Editor();

private slots:
    void setFontColor( QAction * );

private:
    QTextEdit * editor;
    QAction * setRedFont;
};

#endif

Implementation:

/*
$Id$
*/

/* XPM */
static const char * black_xpm[] = {
"32 32 2 1",
"       c None",
".      c #020202",
"................................",
"................................",
"................................",
"................................",
"................................",
"................................",
"................................",
"................................",
"................................",
"................................",
"................................",
"................................",
"................................",
"................................",
"................................",
"................................",
"................................",
"................................",
"................................",
"................................",
"................................",
"................................",
"................................",
"................................",
"................................",
"................................",
"................................",
"................................",
"................................",
"................................",
"................................",
"................................"};

/* XPM */
static const char * red_xpm[] = {
"32 32 6 1",
"       c None",
".      c #EE0928",
"+      c #EF0928",
"@      c #EE0A29",
"#      c #EE0B2A",
"$      c #ED0C2B",
"........................+.......",
".+.++++++++++++++++++++++++++++.",
".++++++++++++++++++++++++++++++.",
".++++++++++++++++++++++++++++++.",
".++++++++++++++++++++++++++++++.",
".++++++++++++++++++++++++++++++.",
".++++++++++++++++++++++++++++++.",
".++++++++.+++++++++++++++++++++.",
".++++++++++++++++++++++++++++++.",
"+++++++++++++++++++++++++++++++.",
".++++++++++++++++++++++++++++++.",
".++++++++++++++++++++++++++++++.",
".++++++++++++++++++++++++++++++.",
".++++++.+++++++++++++++++++++++.",
".++++++++++++++++++++++++++++++.",
".++++++++++++++++++++++++++++++.",
".++++++++++++++++++++++++++++++.",
".++++++++++++++++++++++++++++++.",
".++++++++++++++++.+++++++++++++.",
".++++++++++++++++++++++++++++++.",
".++++++++++++++++++++++++++++++.",
".++++++++++++++++++++++++++++++.",
".++++++++++++++++++++++++++++++@",
".+++++++++++++++++++++++++++++.#",
".+++++++++++++++++++++++++.+++.$",
".+++++++++++++++++++++++++++++#$",
".+++++++++++++++++++++++++++++.#",
".+++++++++++++++++++++++++++++.#",
".++++++++.+++++++++++++++++++++@",
".++++++.+++++++++++++++++++++++.",
".++++++++++++++++++++++++++++++.",
"..........+.............+......."};

#include "editor.h"

#include <qtextedit.h>
#include <qmenubar.h>
#include <qpopupmenu.h>
#include <qtoolbar.h>
#include <qaction.h>

Editor::Editor()
    : QMainWindow( 0, "main window")
{
    QActionGroup * colors = new QActionGroup( this, "colors", TRUE );

    QAction * setBlackFont = new QAction( "black", QPixmap( (const char**)black_xpm ),
                                          "Font color: black", CTRL+Key_B,
                                          colors, "blackfontcolor", TRUE );
    setRedFont = new QAction( "red", QPixmap( (const char**)red_xpm ), "Font color: red",
                              CTRL+Key_R, colors, "redfontcolor", TRUE );

    QObject::connect( colors, SIGNAL( selected( QAction * ) ),
                      this, SLOT( setFontColor( QAction * ) ) );

    QToolBar * toolbar = new QToolBar( this, "toolbar" );
    colors->addTo( toolbar );

    QPopupMenu * font = new QPopupMenu( this );
    menuBar()->insertItem( "&Font", font );

    colors->setUsesDropDown( TRUE );
    colors->setMenuText( "Font Color" );

    colors->addTo( font );

    editor = new QTextEdit( this, "editor" );
    setCentralWidget( editor );
}

void Editor::setFontColor( QAction * coloraction )
{
    if ( coloraction == setRedFont )
        editor->setColor( red );
    else
        editor->setColor( black );
}

See also QAction Examples.


Simple Addressbook

This examples shows how to write a very simple, but complete application using an addressbook as the example.

Header file of the mainwindow:

/****************************************************************************
** $Id:  qt/mainwindow.h   3.0.5   edited Oct 12 2001 $
**
** Copyright ( C ) 1992-2000 Trolltech AS.  All rights reserved.
**
** This file is part of an example program for Qt.  This example
** program may be used, distributed and modified without limitation.
**
*****************************************************************************/

#ifndef AB_MAINWINDOW_H
#define AB_MAINWINDOW_H

#include <qmainwindow.h>
#include <qstring.h>

class QToolBar;
class QPopupMenu;
class ABCentralWidget;

class ABMainWindow: public QMainWindow
{
    Q_OBJECT

public:
    ABMainWindow();
    ~ABMainWindow();

protected slots:
    void fileNew();
    void fileOpen();
    void fileSave();
    void fileSaveAs();
    void filePrint();
    void closeWindow();

protected:
    void setupMenuBar();
    void setupFileTools();
    void setupStatusBar();
    void setupCentralWidget();

    QToolBar *fileTools;
    QString filename;
    ABCentralWidget *view;

};

#endif

Implementation of the mainwindow:

/****************************************************************************
** $Id:  qt/mainwindow.cpp   3.0.5   edited Oct 12 2001 $
**
** Copyright ( C ) 1992-2000 Trolltech AS.  All rights reserved.
**
** This file is part of an example program for Qt.  This example
** program may be used, distributed and modified without limitation.
**
*****************************************************************************/

#include "mainwindow.h"
#include "centralwidget.h"

#include <qtoolbar.h>
#include <qtoolbutton.h>
#include <qpopupmenu.h>
#include <qmenubar.h>
#include <qstatusbar.h>
#include <qapplication.h>
#include <qfiledialog.h>

ABMainWindow::ABMainWindow()
    : QMainWindow( 0, "example addressbook application" ),
      filename( QString::null )
{
    setupMenuBar();
    setupFileTools();
    setupStatusBar();
    setupCentralWidget();
}

ABMainWindow::~ABMainWindow()
{
}

void ABMainWindow::setupMenuBar()
{
    QPopupMenu *file = new QPopupMenu( this );
    menuBar()->insertItem( "&File", file );

    file->insertItem( "New", this, SLOT( fileNew() ), CTRL + Key_N );
    file->insertItem( QPixmap( "fileopen.xpm" ), "Open", this, SLOT( fileOpen() ), CTRL + Key_O );
    file->insertSeparator();
    file->insertItem( QPixmap( "filesave.xpm" ), "Save", this, SLOT( fileSave() ), CTRL + Key_S );
    file->insertItem( "Save As...", this, SLOT( fileSaveAs() ) );
    file->insertSeparator();
    file->insertItem( QPixmap( "fileprint.xpm" ), "Print...", this, SLOT( filePrint() ), CTRL + Key_P );
    file->insertSeparator();
    file->insertItem( "Close", this, SLOT( closeWindow() ), CTRL + Key_W );
    file->insertItem( "Quit", qApp, SLOT( quit() ), CTRL + Key_Q );
}

void ABMainWindow::setupFileTools()
{
    //fileTools = new QToolBar( this, "file operations" );
}

void ABMainWindow::setupStatusBar()
{
    //statusBar()->message( "Ready", 2000 );
}

void ABMainWindow::setupCentralWidget()
{
    view = new ABCentralWidget( this );
    setCentralWidget( view );
}

void ABMainWindow::closeWindow()
{
    close();
}

void ABMainWindow::fileNew()
{
}

void ABMainWindow::fileOpen()
{
    QString fn = QFileDialog::getOpenFileName( QString::null, QString::null, this );
    if ( !fn.isEmpty() ) {
        filename = fn;
        view->load( filename );
    }
}

void ABMainWindow::fileSave()
{
    if ( filename.isEmpty() ) {
        fileSaveAs();
        return;
    }

    view->save( filename );
}

void ABMainWindow::fileSaveAs()
{
    QString fn = QFileDialog::getSaveFileName( QString::null, QString::null, this );
    if ( !fn.isEmpty() ) {
        filename = fn;
        fileSave();
    }
}

void ABMainWindow::filePrint()
{
}

Header file of the centralwidget:

/****************************************************************************
** $Id:  qt/centralwidget.h   3.0.5   edited Oct 12 2001 $
**
** Copyright ( C ) 1992-2000 Trolltech AS.  All rights reserved.
**
** This file is part of an example program for Qt.  This example
** program may be used, distributed and modified without limitation.
**
*****************************************************************************/

#ifndef AB_CENTRALWIDGET_H
#define AB_CENTRALWIDGET_H

#include <qwidget.h>
#include <qstring.h>

class QTabWidget;
class QListView;
class QGridLayout;
class QLineEdit;
class QPushButton;
class QListViewItem;
class QCheckBox;

class ABCentralWidget : public QWidget
{
    Q_OBJECT

public:
    ABCentralWidget( QWidget *parent, const char *name = 0 );

    void save( const QString &filename );
    void load( const QString &filename );

protected slots:
    void addEntry();
    void changeEntry();
    void itemSelected( QListViewItem* );
    void selectionChanged();
    void toggleFirstName();
    void toggleLastName();
    void toggleAddress();
    void toggleEMail();
    void findEntries();

protected:
    void setupTabWidget();
    void setupListView();

    QGridLayout *mainGrid;
    QTabWidget *tabWidget;
    QListView *listView;
    QPushButton *add, *change, *find;
    QLineEdit *iFirstName, *iLastName, *iAddress, *iEMail,
        *sFirstName, *sLastName, *sAddress, *sEMail;
    QCheckBox *cFirstName, *cLastName, *cAddress, *cEMail;

};

#endif

Implementation of the centralwidget:

/****************************************************************************
** $Id:  qt/centralwidget.cpp   3.0.5   edited Apr 3 15:01 $
**
** Copyright ( C ) 1992-2000 Trolltech AS.  All rights reserved.
**
** This file is part of an example program for Qt.  This example
** program may be used, distributed and modified without limitation.
**
*****************************************************************************/

#include "centralwidget.h"

#include <qtabwidget.h>
#include <qlistview.h>
#include <qlayout.h>
#include <qwidget.h>
#include <qlabel.h>
#include <qpushbutton.h>
#include <qlineedit.h>
#include <qlabel.h>
#include <qcheckbox.h>
#include <qfile.h>
#include <qtextstream.h>

ABCentralWidget::ABCentralWidget( QWidget *parent, const char *name )
    : QWidget( parent, name )
{
    mainGrid = new QGridLayout( this, 2, 1, 5, 5 );

    setupTabWidget();
    setupListView();

    mainGrid->setRowStretch( 0, 0 );
    mainGrid->setRowStretch( 1, 1 );
}

void ABCentralWidget::save( const QString &filename )
{
    if ( !listView->firstChild() )
        return;

    QFile f( filename );
    if ( !f.open( IO_WriteOnly ) )
        return;

    QTextStream t( &f );

    QListViewItemIterator it( listView );

    for ( ; it.current(); ++it )
        for ( unsigned int i = 0; i < 4; i++ )
            t << it.current()->text( i ) << "\n";

    f.close();
}

void ABCentralWidget::load( const QString &filename )
{
    listView->clear();

    QFile f( filename );
    if ( !f.open( IO_ReadOnly ) )
        return;

    QTextStream t( &f );

    while ( !t.atEnd() ) {
        QListViewItem *item = new QListViewItem( listView );
        for ( unsigned int i = 0; i < 4; i++ )
            item->setText( i, t.readLine() );
    }

    f.close();
}

void ABCentralWidget::setupTabWidget()
{
    tabWidget = new QTabWidget( this );

    QWidget *input = new QWidget( tabWidget );
    QGridLayout *grid1 = new QGridLayout( input, 2, 5, 5, 5 );

    QLabel *liFirstName = new QLabel( "First &Name", input );
    liFirstName->resize( liFirstName->sizeHint() );
    grid1->addWidget( liFirstName, 0, 0 );

    QLabel *liLastName = new QLabel( "&Last Name", input );
    liLastName->resize( liLastName->sizeHint() );
    grid1->addWidget( liLastName, 0, 1 );

    QLabel *liAddress = new QLabel( "Add&ress", input );
    liAddress->resize( liAddress->sizeHint() );
    grid1->addWidget( liAddress, 0, 2 );

    QLabel *liEMail = new QLabel( "&E-Mail", input );
    liEMail->resize( liEMail->sizeHint() );
    grid1->addWidget( liEMail, 0, 3 );

    add = new QPushButton( "A&dd", input );
    add->resize( add->sizeHint() );
    grid1->addWidget( add, 0, 4 );
    connect( add, SIGNAL( clicked() ), this, SLOT( addEntry() ) );

    iFirstName = new QLineEdit( input );
    iFirstName->resize( iFirstName->sizeHint() );
    grid1->addWidget( iFirstName, 1, 0 );
    liFirstName->setBuddy( iFirstName );

    iLastName = new QLineEdit( input );
    iLastName->resize( iLastName->sizeHint() );
    grid1->addWidget( iLastName, 1, 1 );
    liLastName->setBuddy( iLastName );

    iAddress = new QLineEdit( input );
    iAddress->resize( iAddress->sizeHint() );
    grid1->addWidget( iAddress, 1, 2 );
    liAddress->setBuddy( iAddress );

    iEMail = new QLineEdit( input );
    iEMail->resize( iEMail->sizeHint() );
    grid1->addWidget( iEMail, 1, 3 );
    liEMail->setBuddy( iEMail );

    change = new QPushButton( "&Change", input );
    change->resize( change->sizeHint() );
    grid1->addWidget( change, 1, 4 );
    connect( change, SIGNAL( clicked() ), this, SLOT( changeEntry() ) );

    tabWidget->addTab( input, "&Add/Change Entry" );

    // --------------------------------------

    QWidget *search = new QWidget( this );
    QGridLayout *grid2 = new QGridLayout( search, 2, 5, 5, 5 );

    cFirstName = new QCheckBox( "First &Name", search );
    cFirstName->resize( cFirstName->sizeHint() );
    grid2->addWidget( cFirstName, 0, 0 );
    connect( cFirstName, SIGNAL( clicked() ), this, SLOT( toggleFirstName() ) );

    cLastName = new QCheckBox( "&Last Name", search );
    cLastName->resize( cLastName->sizeHint() );
    grid2->addWidget( cLastName, 0, 1 );
    connect( cLastName, SIGNAL( clicked() ), this, SLOT( toggleLastName() ) );

    cAddress = new QCheckBox( "Add&ress", search );
    cAddress->resize( cAddress->sizeHint() );
    grid2->addWidget( cAddress, 0, 2 );
    connect( cAddress, SIGNAL( clicked() ), this, SLOT( toggleAddress() ) );

    cEMail = new QCheckBox( "&E-Mail", search );
    cEMail->resize( cEMail->sizeHint() );
    grid2->addWidget( cEMail, 0, 3 );
    connect( cEMail, SIGNAL( clicked() ), this, SLOT( toggleEMail() ) );

    sFirstName = new QLineEdit( search );
    sFirstName->resize( sFirstName->sizeHint() );
    grid2->addWidget( sFirstName, 1, 0 );

    sLastName = new QLineEdit( search );
    sLastName->resize( sLastName->sizeHint() );
    grid2->addWidget( sLastName, 1, 1 );

    sAddress = new QLineEdit( search );
    sAddress->resize( sAddress->sizeHint() );
    grid2->addWidget( sAddress, 1, 2 );

    sEMail = new QLineEdit( search );
    sEMail->resize( sEMail->sizeHint() );
    grid2->addWidget( sEMail, 1, 3 );

    find = new QPushButton( "F&ind", search );
    find->resize( find->sizeHint() );
    grid2->addWidget( find, 1, 4 );
    connect( find, SIGNAL( clicked() ), this, SLOT( findEntries() ) );

    cFirstName->setChecked( TRUE );
    sFirstName->setEnabled( TRUE );
    sLastName->setEnabled( FALSE );
    sAddress->setEnabled( FALSE );
    sEMail->setEnabled( FALSE );

    tabWidget->addTab( search, "&Search" );

    mainGrid->addWidget( tabWidget, 0, 0 );
}

void ABCentralWidget::setupListView()
{
    listView = new QListView( this );
    listView->addColumn( "First Name" );
    listView->addColumn( "Last Name" );
    listView->addColumn( "Address" );
    listView->addColumn( "E-Mail" );

    listView->setSelectionMode( QListView::Single );

    connect( listView, SIGNAL( clicked( QListViewItem* ) ), this, SLOT( itemSelected( QListViewItem* ) ) );

    mainGrid->addWidget( listView, 1, 0 );
    listView->setAllColumnsShowFocus( TRUE );
}

void ABCentralWidget::addEntry()
{
    if ( !iFirstName->text().isEmpty() || !iLastName->text().isEmpty() ||
         !iAddress->text().isEmpty() || !iEMail->text().isEmpty() ) {
        QListViewItem *item = new QListViewItem( listView );
        item->setText( 0, iFirstName->text() );
        item->setText( 1, iLastName->text() );
        item->setText( 2, iAddress->text() );
        item->setText( 3, iEMail->text() );
    }

    iFirstName->setText( "" );
    iLastName->setText( "" );
    iAddress->setText( "" );
    iEMail->setText( "" );
}

void ABCentralWidget::changeEntry()
{
    QListViewItem *item = listView->currentItem();

    if ( item &&
         ( !iFirstName->text().isEmpty() || !iLastName->text().isEmpty() ||
           !iAddress->text().isEmpty() || !iEMail->text().isEmpty() ) ) {
        item->setText( 0, iFirstName->text() );
        item->setText( 1, iLastName->text() );
        item->setText( 2, iAddress->text() );
        item->setText( 3, iEMail->text() );
    }
}

void ABCentralWidget::selectionChanged()
{
    iFirstName->setText( "" );
    iLastName->setText( "" );
    iAddress->setText( "" );
    iEMail->setText( "" );
}

void ABCentralWidget::itemSelected( QListViewItem *item )
{
    if ( !item )
        return;
    item->setSelected( TRUE );
    item->repaint();

    iFirstName->setText( item->text( 0 ) );
    iLastName->setText( item->text( 1 ) );
    iAddress->setText( item->text( 2 ) );
    iEMail->setText( item->text( 3 ) );
}

void ABCentralWidget::toggleFirstName()
{
    sFirstName->setText( "" );

    if ( cFirstName->isChecked() ) {
        sFirstName->setEnabled( TRUE );
        sFirstName->setFocus();
    }
    else
        sFirstName->setEnabled( FALSE );
}

void ABCentralWidget::toggleLastName()
{
    sLastName->setText( "" );

    if ( cLastName->isChecked() ) {
        sLastName->setEnabled( TRUE );
        sLastName->setFocus();
    }
    else
        sLastName->setEnabled( FALSE );
}

void ABCentralWidget::toggleAddress()
{
    sAddress->setText( "" );

    if ( cAddress->isChecked() ) {
        sAddress->setEnabled( TRUE );
        sAddress->setFocus();
    }
    else
        sAddress->setEnabled( FALSE );
}

void ABCentralWidget::toggleEMail()
{
    sEMail->setText( "" );

    if ( cEMail->isChecked() ) {
        sEMail->setEnabled( TRUE );
        sEMail->setFocus();
    }
    else
        sEMail->setEnabled( FALSE );
}

void ABCentralWidget::findEntries()
{
    if ( !cFirstName->isChecked() &&
         !cLastName->isChecked() &&
         !cAddress->isChecked() &&
         !cEMail->isChecked() ) {
        listView->clearSelection();
        return;
    }

    QListViewItemIterator it( listView );

    for ( ; it.current(); ++it ) {
        bool select = TRUE;

        if ( cFirstName->isChecked() ) {
            if ( select && it.current()->text( 0 ).contains( sFirstName->text() ) )
                select = TRUE;
            else
                select = FALSE;
        }
        if ( cLastName->isChecked() ) {
            if ( select && it.current()->text( 1 ).contains( sLastName->text() ) )
                select = TRUE;
            else
                select = FALSE;
        }
        if ( cAddress->isChecked() ) {
            if ( select && it.current()->text( 2 ).contains( sAddress->text() ) )
                select = TRUE;
            else
                select = FALSE;
        }
        if ( cEMail->isChecked() ) {
            if ( select && it.current()->text( 3 ).contains( sEMail->text() ) )
                select = TRUE;
            else
                select = FALSE;
        }

        if ( select )
            it.current()->setSelected( TRUE );
        else
            it.current()->setSelected( FALSE );
        it.current()->repaint();
    }
}

Main:

/****************************************************************************
** $Id:  qt/main.cpp   3.0.5   edited Oct 12 2001 $
**
** Copyright ( C ) 1992-2000 Trolltech AS.  All rights reserved.
**
** This file is part of an example program for Qt.  This example
** program may be used, distributed and modified without limitation.
**
*****************************************************************************/

#include <qapplication.h>

#include "mainwindow.h"

int main( int argc, char ** argv )
{
    QApplication a( argc, argv );

    ABMainWindow *mw = new ABMainWindow();
    mw->setCaption( "Qt Example - Addressbook" );
    a.setMainWidget( mw );
    mw->show();

    a.connect( &a, SIGNAL( lastWindowClosed() ), &a, SLOT( quit() ) );
    int result = a.exec();
    delete mw;
    return result;
}

See also Examples.


Advanced Widgets

These classes provide more complex user interface controls (widgets).

QCheckListItem | Checkable list view items
QCheckTableItem | Checkboxes in QTables
QComboTableItem | Means of using comboboxes in QTables
QDateEdit | Date editor
QDateTimeEdit | Combines a QDateEdit and QTimeEdit widget into a single widget for editing datetimes
QDesktopWidget | Access to screen information on multi-head systems
QEditorFactory | Used to create editor widgets for QVariant data types
QHeader | Header row or column, e.g. for tables and listviews
QIconView | Area with movable labelled icons
QIconViewItem | Single item in a QIconView
QListBox | List of selectable, read-only items
QListBoxItem | The base class of all list box items
QListBoxPixmap | List box items with a pixmap and optional text
QListBoxText | List box items that display text
QListView | Implements a list/tree view
QListViewItem | Implements a list view item
QListViewItemIterator | Iterator for collections of QListViewItems
QMultiLineEdit | Simple editor for inputting text
QProgressBar | Horizontal progress bar
QTab | The structures in a QTabBar
QTabBar | Tab bar, e.g. for use in tabbed dialogs
QTable | Flexible editable table widget
QTableItem | The cell content for QTable cells
QTableSelection | Access to a selected area in a QTable
QTabWidget | Stack of tabbed widgets
QTextBrowser | Rich text browser with hypertext navigation
QTimeEdit | Time editor


Widget Appearance and Style

These classes are used to customize an application's appearance and style.

QBoxLayout | Lines up child widgets horizontally or vertically
QButtonGroup | Organizes QButton widgets in a group
QCDEStyle | CDE look and feel
QColor | Colors based on RGB or HSV values
QColorGroup | Group of widget colors
QCommonStyle | Encapsulates the common Look and Feel of a GUI
QCursor | Mouse cursor with an arbitrary shape
QFont | Font used for drawing text
QGLayoutIterator | Abstract base class of internal layout iterators
QGrid | Simple geometry management of its children
QGridLayout | Lays out widgets in a grid
QGroupBox | Group box frame with a title
QHBox | Horizontal geometry management for its child widgets
QHBoxLayout | Lines up widgets horizontally
QHButtonGroup | Organizes QButton widgets in a group with one horizontal row
QHGroupBox | Organizes widgets in a group with one horizontal row
QLayout | The base class of geometry managers
QLayoutItem | Abstract item that a QLayout manipulates
QLayoutIterator | Iterators over QLayoutItem
QMotifPlusStyle | More sophisticated Motif-ish look and feel
QMotifStyle | Motif look and feel
QPalette | Color groups for each widget state
QPlatinumStyle | Mac/Platinum look and feel
QSGIStyle | SGI/Irix look and feel
QSizeGrip | Corner-grip for resizing a top-level window
QSizePolicy | Layout attribute describing horizontal and vertical resizing policy
QSpacerItem | Blank space in a layout
QStyle | The look and feel of a GUI
QStyleOption | Optional parameters for QStyle functions
QVBox | Vertical geometry management of its child widgets
QVBoxLayout | Lines up widgets vertically
QVButtonGroup | Organizes QButton widgets in a vertical column
QVGroupBox | Organizes a group of widgets in a vertical column
QWidgetItem | Layout item that represents a widget
QWindowsStyle | Microsoft Windows-like look and feel


Setting the Application Icon

The application icon, typically displayed in the upper left corner of the application top-level windows, is set by calling the QWidget::setIcon() method on top-level widgets.

In order to change the icon of the executable application file itself, as it is presented on the desktop (i.e. prior to application execution), it is necessary to employ another, platform-dependent technique.

  • Setting the Application Icon on Windows
  • Setting the Application Icon on Mac OS X

Setting the Application Icon on Windows

First, create an ICO format bitmap file that contains the icon image. This can be done with e.g. Microsoft Visual C++: Select "File|New...", then select the "File" tab in the dialog that appears, and choose "Icon". (Note that you do not need to load your application into Visual C++; here we are only using its icon editor).

Store the ICO file in the source code directory of your application, for example, with the name, "myappico.ico". Then, create a text file called e.g. "myapp.rc" in which you put a single line of text:

IDI_ICON1               ICON    DISCARDABLE     "myappico.ico"

Lastly, assuming you are using qmake to generate your makefiles, add this line to your "myapp.pro" file:

RC_FILE = myapp.rc

Regenerate your makefile and your application. The .exe file will now be represented with your icon in e.g. Explorer.

If you do not use qmake, the necessary steps are: first, run the "rc" program on the .rc file, then link your application with the resulting .res file.

Setting the Application Icon on Mac OS X

The application icon, typically displayed in the application dock area, is set by calling QWidget::setIcon() on a top-level widget. It is possible that the program could appear in the application dock area before the function call, in which case a default icon will appear during the bouncing animation.

To ensure that the correct icon appears, both when the application is being launched, and in the finder, it is necessary to employ a platform-dependent technique.

Although many programs can create icon files (.icns), the recommended approach is to use the Icon Composer program supplied by Apple (in the Developer/Application folder). Icon Composer allows you to import several different sized icons (for use in different contexts) as well as the masks that go with them. Save the set of icons to a file in your project directory.

If you are using qmake to generate your make files, you only need to add a single line to your .pro project file. For example, if the name of your icon file is myapp.icns, and your project file is myapp.pro, add this line to myapp.pro:

RC_FILE = myapp.icns
This will ensure that qmake puts your icons in the proper place and creates a Info.plist entry for the icon.

If you do not use qmake, you must do the following manually:

  1. Create an Info.plist file for your application (using the PropertyListEditor, found in Developer/Applications).
  2. Associate your .icns record with the CFBundleIconFile record in the Info.plist file (again, using the PropertyListEditor).
  3. Copy both the icns and your Info.plist into your application bundle Resource directory.


Main Window and Related Classes

These classes provide everything you need for a typical modern main application window, like the main window itself, menu and tool bars, a statusbar, etc.

QAction | Abstract user interface action that can appear both in menus and tool bars
QActionGroup | Groups actions together
QApplication | Manages the GUI application's control flow and main settings
QDockArea | Manages and lays out QDockWindows
QDockWindow | Widget which can be docked inside a QDockArea or floated as a top level window on the desktop
QMainWindow | Main application window, with a menu bar, dock windows (e.g. for toolbars), and a status bar
QMenuBar | Horizontal menu bar
QPopupMenu | Popup menu widget
QSessionManager | Access to the session manager
QSizeGrip | Corner-grip for resizing a top-level window
QStatusBar | Horizontal bar suitable for presenting status information
QToolBar | Movable panel containing widgets such as tool buttons
QWorkspace | Workspace window that can contain decorated windows, e.g. for MDI


Basic Widgets

These basic controls (widgets) are designed for direct use. There are also some abstract widget classes, designed for subclassing, and some more complex widgets.

QAction | Abstract user interface action that can appear both in menus and tool bars
QActionGroup | Groups actions together
QCheckBox | Checkbox with a text label
QComboBox | Combined button and popup list
QDial | Rounded range control (like a speedometer or potentiometer)
QLabel | Text or image display
QLCDNumber | Displays a number with LCD-like digits
QLineEdit | One-line text editor
QPopupMenu | Popup menu widget
QPushButton | Command button
QRadioButton | Radio button with a text or pixmap label
QScrollBar | Vertical or horizontal scroll bar
QSizeGrip | Corner-grip for resizing a top-level window
QSlider | Vertical or horizontal slider
QSpinBox | Spin box widget (spin button)
QTextEdit | Powerful single-page rich text editor
QToolButton | Quick-access button to commands or options, usually used inside a QToolBar


Biff (UNIX only)

Biff is a simple graphical program to indicate whether there is new mail; it looks exactly like xbiff but is much shorter.

Header file:

/****************************************************************************
** $Id:  qt/biff.h   3.0.5   edited Oct 12 2001 $
**
** Copyright (C) 1992-2000 Trolltech AS.  All rights reserved.
**
** This file is part of an example program for Qt.  This example
** program may be used, distributed and modified without limitation.
**
*****************************************************************************/

#ifndef BIFF_H
#define BIFF_H

#include <qwidget.h>
#include <qdatetime.h>
#include <qpixmap.h>

class Biff : public QWidget
{
    Q_OBJECT
public:
    Biff( QWidget *parent=0, const char *name=0 );

protected:
    void        timerEvent( QTimerEvent * );
    void        paintEvent( QPaintEvent * );
    void        mousePressEvent( QMouseEvent * );

private:
    QDateTime   lastModified;
    QPixmap     hasNewMail;
    QPixmap     noNewMail;
    QString     mailbox;
    bool        gotMail;
};

#endif // BIFF_H

biff.cpp implements this custom widget. Note in particular how two images (hasmail_bmp_data and nomail_bmp_data, both from bmp.cpp) are included into the executable.

/****************************************************************************
** $Id:  qt/biff.cpp   3.0.5   edited Oct 12 2001 $
**
** Copyright (C) 1992-2000 Trolltech AS.  All rights reserved.
**
** This file is part of an example program for Qt.  This example
** program may be used, distributed and modified without limitation.
**
*****************************************************************************/

#include "biff.h"
#include <qstring.h>
#include <qfileinfo.h>
#include <qpainter.h>

#include <unistd.h>
#include <stdlib.h>

#include "bmp.cpp"

Biff::Biff( QWidget *parent, const char *name )
    : QWidget( parent, name, WType_Modal )
{
    QFileInfo fi = QString(getenv( "MAIL" ));
    if ( !fi.exists() ) {
        QString s( "/var/spool/mail/" );
        s += getlogin();
        fi.setFile( s );
    }

    if ( fi.exists() ) {
        mailbox = fi.absFilePath();
        startTimer( 1000 );
    }

    setMinimumSize( 48, 48 );
    setMaximumSize( 48, 48 );
    resize( 48, 48 );

    hasNewMail.loadFromData( hasmail_bmp_data, hasmail_bmp_len );
    noNewMail.loadFromData( nomail_bmp_data, nomail_bmp_len );

    gotMail = FALSE;
    lastModified = fi.lastModified();
}

void Biff::timerEvent( QTimerEvent * )
{
    QFileInfo fi( mailbox );
    bool newState = ( fi.lastModified() != lastModified &&
                      fi.lastModified() > fi.lastRead() );
    if ( newState != gotMail ) {
        if ( gotMail )
            lastModified = fi.lastModified();
        gotMail = newState;
        repaint( FALSE );
    }
}

void Biff::paintEvent( QPaintEvent * )
{
    if ( gotMail )
        bitBlt( this, 0, 0, &hasNewMail );
    else
        bitBlt( this, 0, 0, &noNewMail );
}

void Biff::mousePressEvent( QMouseEvent * )
{
    QFileInfo fi( mailbox );
    lastModified = fi.lastModified();
}

Main:

/****************************************************************************
** $Id:  qt/main.cpp   3.0.5   edited Oct 12 2001 $
**
** Copyright (C) 1992-2000 Trolltech AS.  All rights reserved.
**
** This file is part of an example program for Qt.  This example
** program may be used, distributed and modified without limitation.
**
*****************************************************************************/

#include <qapplication.h>
#include "biff.h"

int main( int argc, char ** argv )
{
    QApplication a( argc, argv );
    Biff b;
    a.setMainWidget( &b );
    b.show();
    return a.exec();
}

See also Examples.


如何生成大的稀疏QTable

本样例显示一个稀疏表格的实现，它使用QIntDict以跟踪实际使用的单元格的记录。

实现：

/****************************************************************************
** $Id:  qt/main.cpp   3.0.5   edited Oct 12 2001 $
**
** Copyright (C) 1992-2000 Trolltech AS.  All rights reserved.
**
** This file is part of an example program for Qt.  This example
** program may be used, distributed and modified without limitation.
**
*****************************************************************************/

#include <qapplication.h>
#include <qtable.h>

// Table size

const int numRows = 1000000;
const int numCols = 1000000;

class MyTable : public QTable
{
public:
    MyTable( int r, int c ) : QTable( r, c ) {
        items.setAutoDelete( TRUE );
        widgets.setAutoDelete( TRUE );
        setCaption( tr( "This is a big table with 1.000.000x1.000.000 cells..." ) );
        setLeftMargin( fontMetrics().width( "W999999W" ) );
    }

    void resizeData( int ) {}
    QTableItem *item( int r, int c ) const { return items.find( indexOf( r, c ) ); }
    void setItem( int r, int c, QTableItem *i ) { items.replace( indexOf( r, c ), i ); }
    void clearCell( int r, int c ) { items.remove( indexOf( r, c ) ); }
    void insertWidget( int r, int c, QWidget *w ) { widgets.replace( indexOf( r, c ), w );  }
    QWidget *cellWidget( int r, int c ) const { return widgets.find( indexOf( r, c ) ); }
    void clearCellWidget( int r, int c ) { widgets.remove( indexOf( r, c ) ); }

private:
    QIntDict<QTableItem> items;
    QIntDict<QWidget> widgets;

};

// The program starts here.

int main( int argc, char **argv )
{
    QApplication app( argc, argv );

    MyTable table( numRows, numCols );
    app.setMainWidget( &table );
    table.show();
    return app.exec();
}

也参见表格例程。

Copyright © 2002 Trolltech Trademarks 译者:farfareast
Qt 3.0.5版


Buttons and Groupboxes

This example shows different types of groupboxes (buttongroups, etc.) and different kinds of buttons (checkboxes, radiobuttons, pushbuttons, etc.).

Header file:

/****************************************************************************
** $Id:  qt/buttongroups.h   3.0.5   edited Oct 12 2001 $
**
** Copyright (C) 1992-2000 Trolltech AS.  All rights reserved.
**
** This file is part of an example program for Qt.  This example
** program may be used, distributed and modified without limitation.
**
*****************************************************************************/

#ifndef BUTTONS_GROUPS_H
#define BUTTONS_GROUPS_H

#include <qwidget.h>

class QCheckBox;
class QRadioButton;

class ButtonsGroups : public QWidget
{
    Q_OBJECT

public:
    ButtonsGroups( QWidget *parent = 0, const char *name = 0 );

protected:
    QCheckBox *state;
    QRadioButton *rb21, *rb22, *rb23;

protected slots:
    void slotChangeGrp3State();

};

#endif

Implementation:

/****************************************************************************
** $Id:  qt/buttongroups.cpp   3.0.5   edited Jun 4 09:54 $
**
** Copyright (C) 1992-2000 Trolltech AS.  All rights reserved.
**
** This file is part of an example program for Qt.  This example
** program may be used, distributed and modified without limitation.
**
*****************************************************************************/

#include "buttongroups.h"

#include <qbuttongroup.h>
#include <qlayout.h>
#include <qradiobutton.h>
#include <qcheckbox.h>
#include <qgroupbox.h>
#include <qpushbutton.h>

/*
 * Constructor
 *
 * Creates all child widgets of the ButtonGroups window
 */

ButtonsGroups::ButtonsGroups( QWidget *parent, const char *name )
    : QWidget( parent, name )
{
    // Create Widgets which allow easy layouting
    QVBoxLayout *vbox = new QVBoxLayout( this, 11, 6 );
    QHBoxLayout *box1 = new QHBoxLayout( vbox );
    QHBoxLayout *box2 = new QHBoxLayout( vbox );

    // ------- first group

    // Create an exclusive button group
    QButtonGroup *bgrp1 = new QButtonGroup( 1, QGroupBox::Horizontal, "Button Group &1 (exclusive)", this);
    box1->addWidget( bgrp1 );
    bgrp1->setExclusive( TRUE );

    // insert 3 radiobuttons
    QRadioButton *rb11 = new QRadioButton( "&Radiobutton 1", bgrp1 );
    rb11->setChecked( TRUE );
    (void)new QRadioButton( "R&adiobutton 2", bgrp1 );
    (void)new QRadioButton( "Ra&diobutton 3", bgrp1 );

    // ------- second group

    // Create a non-exclusive buttongroup
    QButtonGroup *bgrp2 = new QButtonGroup( 1, QGroupBox::Horizontal, "Button Group &2 (non-exclusive)", this );
    box1->addWidget( bgrp2 );
    bgrp2->setExclusive( FALSE );

    // insert 3 checkboxes
    (void)new QCheckBox( "&Checkbox 1", bgrp2 );
    QCheckBox *cb12 = new QCheckBox( "C&heckbox 2", bgrp2 );
    cb12->setChecked( TRUE );
    QCheckBox *cb13 = new QCheckBox( "Triple &State Button", bgrp2 );
    cb13->setTristate( TRUE );
    cb13->setChecked( TRUE );

    // ------------ third group

    // create a buttongroup which is exclusive for radiobuttons and non-exclusive for all other buttons
    QButtonGroup *bgrp3 = new QButtonGroup( 1, QGroupBox::Horizontal, "Button Group &3 (Radiobutton-exclusive)", this );
    box2->addWidget( bgrp3 );
    bgrp3->setRadioButtonExclusive( TRUE );

    // insert three radiobuttons
    rb21 = new QRadioButton( "Rad&iobutton 1", bgrp3 );
    rb22 = new QRadioButton( "Radi&obutton 2", bgrp3 );
    rb23 = new QRadioButton( "Radio&button 3", bgrp3 );
    rb23->setChecked( TRUE );

    // insert a checkbox...
    state = new QCheckBox( "E&nable Radiobuttons", bgrp3 );
    state->setChecked( TRUE );
    // ...and connect its SIGNAL clicked() with the SLOT slotChangeGrp3State()
    connect( state, SIGNAL( clicked() ), this, SLOT( slotChangeGrp3State() ) );

    // ------------ fourth group

    // create a groupbox which layouts its childs in a columns
    QGroupBox *bgrp4 = new QButtonGroup( 1, QGroupBox::Horizontal, "Groupbox with &normal buttons", this );
    box2->addWidget( bgrp4 );

    // insert three pushbuttons...
    (void)new QPushButton( "&Push Button", bgrp4 );
    QPushButton *tb2 = new QPushButton( "&Toggle Button", bgrp4 );
    QPushButton *tb3 = new QPushButton( "&Flat Button", bgrp4 );

    // ... and make the second one a toggle button
    tb2->setToggleButton( TRUE );
    tb2->setOn( TRUE );

    // ... and make the third one a flat button
    tb3->setFlat(TRUE);
}

/*
 * SLOT slotChangeGrp3State()
 *
 * enables/disables the radiobuttons of the third buttongroup
 */

void ButtonsGroups::slotChangeGrp3State()
{
    rb21->setEnabled( state->isChecked() );
    rb22->setEnabled( state->isChecked() );
    rb23->setEnabled( state->isChecked() );
}

Main:

/****************************************************************************
** $Id:  qt/main.cpp   3.0.5   edited Oct 12 2001 $
**
** Copyright (C) 1992-2000 Trolltech AS.  All rights reserved.
**
** This file is part of an example program for Qt.  This example
** program may be used, distributed and modified without limitation.
**
*****************************************************************************/

#include "buttongroups.h"
#include <qapplication.h>

int main( int argc, char **argv )
{
    QApplication a( argc, argv );

    ButtonsGroups buttonsgroups;
    buttonsgroups.resize( 500, 250 );
    buttonsgroups.setCaption( "Qt Example - Buttongroups" );
    a.setMainWidget( &buttonsgroups );
    buttonsgroups.show();

    return a.exec();
}

See also Examples.


A Complete Canvas Application

This is a complete example program with a main window, menus and toolbars. The main widget is a QCanvas, and this example demonstrates basic canvas usage.

Project file:

TEMPLATE = app
CONFIG  += warn_on

HEADERS +=  element.h \
            canvastext.h \
            canvasview.h \
            chartform.h \
            optionsform.h \
            setdataform.h
SOURCES +=  element.cpp \
            canvasview.cpp \
            chartform.cpp \
            chartform_canvas.cpp \
            chartform_files.cpp \
            optionsform.cpp \
            setdataform.cpp \
            main.cpp

Header files:

#ifndef ELEMENT_H
#define ELEMENT_H

#include <qcolor.h>
#include <qnamespace.h>
#include <qstring.h>
#include <qvaluevector.h>

class Element;

typedef QValueVector<Element> ElementVector;

/*
    Elements are valid if they have a value which is > EPSILON.
*/
const double EPSILON = 0.0000001; // Must be > INVALID.

class Element
{
public:
    enum { INVALID = -1 };
    enum { NO_PROPORTION = -1 };
    enum { MAX_PROPOINTS = 3 }; // One proportional point per chart type

    Element( double value = INVALID, QColor valueColor = Qt::gray,
             int valuePattern = Qt::SolidPattern,
             const QString& label = QString::null,
             QColor labelColor = Qt::black ) {
        init( value, valueColor, valuePattern, label, labelColor );
        for ( int i = 0; i < MAX_PROPOINTS * 2; ++i )
            m_propoints[i] = NO_PROPORTION;
    }
    ~Element() {}

    bool isValid() const { return m_value > EPSILON; }

    double value() const { return m_value; }
    QColor valueColor() const { return m_valueColor; }
    int valuePattern() const { return m_valuePattern; }
    QString label() const { return m_label; }
    QColor labelColor() const { return m_labelColor; }
    double proX( int index ) const;
    double proY( int index ) const;

    void set( double value = INVALID, QColor valueColor = Qt::gray,
              int valuePattern = Qt::SolidPattern,
              const QString& label = QString::null,
              QColor labelColor = Qt::black ) {
        init( value, valueColor, valuePattern, label, labelColor );
    }
    void setValue( double value ) { m_value = value; }
    void setValueColor( QColor valueColor ) { m_valueColor = valueColor; }
    void setValuePattern( int valuePattern );
    void setLabel( const QString& label ) { m_label = label; }
    void setLabelColor( QColor labelColor ) { m_labelColor = labelColor; }
    void setProX( int index, double value );
    void setProY( int index, double value );

private:
    void init( double value, QColor valueColor, int valuePattern,
               const QString& label, QColor labelColor );

    double m_value;
    QColor m_valueColor;
    int m_valuePattern;
    QString m_label;
    QColor m_labelColor;
    double m_propoints[2 * MAX_PROPOINTS];
};

Q_EXPORT QTextStream &operator<<( QTextStream&, const Element& );
Q_EXPORT QTextStream &operator>>( QTextStream&, Element& );

#endif

#ifndef CHARTFORM_H
#define CHARTFORM_H

#include "element.h"

#include <qmainwindow.h>
#include <qstringlist.h>

class CanvasView;

class QAction;
class QCanvas;
class QFont;
class QPrinter;
class QString;

class ChartForm: public QMainWindow
{
    Q_OBJECT
public:
    enum { MAX_ELEMENTS = 100 };
    enum { MAX_RECENTFILES = 9 }; // Must not exceed 9
    enum ChartType { PIE, VERTICAL_BAR, HORIZONTAL_BAR };
    enum AddValuesType { NO, YES, AS_PERCENTAGE };

    ChartForm( const QString& filename );
    ~ChartForm();

    int chartType() { return m_chartType; }
    void setChanged( bool changed = true ) { m_changed = changed; }
    void drawElements();

    QPopupMenu *optionsMenu; // Why public? See canvasview.cpp

private slots:
    void fileNew();
    void fileOpen();
    void fileOpenRecent( int index );
    void fileSave();
    void fileSaveAs();
    void fileSaveAsPixmap();
    void filePrint();
    void fileQuit();
    void optionsSetData();
    void updateChartType( QAction *action );
    void optionsSetFont();
    void optionsSetOptions();
    void helpHelp();
    void helpAbout();
    void helpAboutQt();
    void saveOptions();

private:
    void init();
    void load( const QString& filename );
    bool okToClear();
    void drawPieChart( const double scales[], double total, int count );
    void drawVerticalBarChart( const double scales[], double total, int count );
    void drawHorizontalBarChart( const double scales[], double total, int count );

    QString valueLabel( const QString& label, double value, double total );
    void updateRecentFiles( const QString& filename );
    void updateRecentFilesMenu();
    void setChartType( ChartType chartType );

    QPopupMenu *fileMenu;
    QAction *optionsPieChartAction;
    QAction *optionsHorizontalBarChartAction;
    QAction *optionsVerticalBarChartAction;

    QString m_filename;
    QStringList m_recentFiles;
    QCanvas *m_canvas;
    CanvasView *m_canvasView;
    bool m_changed;
    ElementVector m_elements;
    QPrinter *m_printer;
    ChartType m_chartType;
    AddValuesType m_addValues;
    int m_decimalPlaces;
    QFont m_font;
};

#endif

 Implementation:

#include "canvasview.h"
#include "chartform.h"
#include "optionsform.h"
#include "setdataform.h"

#include <qaction.h>
#include <qapplication.h>
#include <qcombobox.h>
#include <qfile.h>
#include <qfiledialog.h>
#include <qfont.h>
#include <qfontdialog.h>
#include <qmenubar.h>
#include <qmessagebox.h>
#include <qpixmap.h>
#include <qpopupmenu.h>
#include <qprinter.h>
#include <qradiobutton.h>
#include <qsettings.h>
#include <qspinbox.h>
#include <qstatusbar.h>
#include <qtoolbar.h>
#include <qtoolbutton.h>

#include "images/file_new.xpm"
#include "images/file_open.xpm"
#include "images/file_save.xpm"
#include "images/file_print.xpm"
#include "images/options_setdata.xpm"
#include "images/options_setfont.xpm"
#include "images/options_setoptions.xpm"
#include "images/options_horizontalbarchart.xpm"
#include "images/options_piechart.xpm"
#include "images/options_verticalbarchart.xpm"

const QString WINDOWS_REGISTRY = "/QtExamples";
const QString APP_KEY = "/Chart/";

ChartForm::ChartForm( const QString& filename )
    : QMainWindow( 0, 0, WDestructiveClose )
{
    setIcon( QPixmap( options_piechart ) );

    QAction *fileNewAction;
    QAction *fileOpenAction;
    QAction *fileSaveAction;
    QAction *fileSaveAsAction;
    QAction *fileSaveAsPixmapAction;
    QAction *filePrintAction;
    QAction *fileQuitAction;
    QAction *optionsSetDataAction;
    QAction *optionsSetFontAction;
    QAction *optionsSetOptionsAction;

    fileNewAction = new QAction(
            "New Chart", QPixmap( file_new ),
            "&New", CTRL+Key_N, this, "new" );
    connect( fileNewAction, SIGNAL( activated() ), this, SLOT( fileNew() ) );

    fileOpenAction = new QAction(
            "Open Chart", QPixmap( file_open ),
            "&Open...", CTRL+Key_O, this, "open" );
    connect( fileOpenAction, SIGNAL( activated() ), this, SLOT( fileOpen() ) );

    fileSaveAction = new QAction(
            "Save Chart", QPixmap( file_save ),
            "&Save", CTRL+Key_S, this, "save" );
    connect( fileSaveAction, SIGNAL( activated() ), this, SLOT( fileSave() ) );

    fileSaveAsAction = new QAction(
            "Save Chart As", QPixmap( file_save ),
            "Save &As...", 0, this, "save as" );
    connect( fileSaveAsAction, SIGNAL( activated() ),
             this, SLOT( fileSaveAs() ) );

    fileSaveAsPixmapAction = new QAction(
            "Save Chart As Bitmap", QPixmap( file_save ),
            "Save As &Bitmap...", CTRL+Key_B, this, "save as bitmap" );
    connect( fileSaveAsPixmapAction, SIGNAL( activated() ),
             this, SLOT( fileSaveAsPixmap() ) );

    filePrintAction = new QAction(
            "Print Chart", QPixmap( file_print ),
            "&Print Chart...", CTRL+Key_P, this, "print chart" );
    connect( filePrintAction, SIGNAL( activated() ),
             this, SLOT( filePrint() ) );

    optionsSetDataAction = new QAction(
            "Set Data", QPixmap( options_setdata ),
            "Set &Data...", CTRL+Key_D, this, "set data" );
    connect( optionsSetDataAction, SIGNAL( activated() ),
             this, SLOT( optionsSetData() ) );

    QActionGroup *chartGroup = new QActionGroup( this ); // Connected later
    chartGroup->setExclusive( true );

    optionsPieChartAction = new QAction(
            "Pie Chart", QPixmap( options_piechart ),
            "&Pie Chart", CTRL+Key_I, chartGroup, "pie chart" );
    optionsPieChartAction->setToggleAction( true );

    optionsHorizontalBarChartAction = new QAction(
            "Horizontal Bar Chart", QPixmap( options_horizontalbarchart ),
            "&Horizontal Bar Chart", CTRL+Key_H, chartGroup,
            "horizontal bar chart" );
    optionsHorizontalBarChartAction->setToggleAction( true );

    optionsVerticalBarChartAction = new QAction(
            "Vertical Bar Chart", QPixmap( options_verticalbarchart ),
            "&Vertical Bar Chart", CTRL+Key_V, chartGroup, "Vertical bar chart" );
    optionsVerticalBarChartAction->setToggleAction( true );

    optionsSetFontAction = new QAction(
            "Set Font", QPixmap( options_setfont ),
            "Set &Font...", CTRL+Key_F, this, "set font" );
    connect( optionsSetFontAction, SIGNAL( activated() ),
             this, SLOT( optionsSetFont() ) );

    optionsSetOptionsAction = new QAction(
            "Set Options", QPixmap( options_setoptions ),
            "Set &Options...", 0, this, "set options" );
    connect( optionsSetOptionsAction, SIGNAL( activated() ),
             this, SLOT( optionsSetOptions() ) );

    fileQuitAction = new QAction( "Quit", "&Quit", CTRL+Key_Q, this, "quit" );
    connect( fileQuitAction, SIGNAL( activated() ), this, SLOT( fileQuit() ) );

    QToolBar* fileTools = new QToolBar( this, "file operations" );
    fileTools->setLabel( "File Operations" );
    fileNewAction->addTo( fileTools );
    fileOpenAction->addTo( fileTools );
    fileSaveAction->addTo( fileTools );
    fileTools->addSeparator();
    filePrintAction->addTo( fileTools );

    QToolBar *optionsTools = new QToolBar( this, "options operations" );
    optionsTools->setLabel( "Options Operations" );
    optionsSetDataAction->addTo( optionsTools );
    optionsTools->addSeparator();
    optionsPieChartAction->addTo( optionsTools );
    optionsHorizontalBarChartAction->addTo( optionsTools );
    optionsVerticalBarChartAction->addTo( optionsTools );
    optionsTools->addSeparator();
    optionsSetFontAction->addTo( optionsTools );
    optionsTools->addSeparator();
    optionsSetOptionsAction->addTo( optionsTools );

    fileMenu = new QPopupMenu( this );
    menuBar()->insertItem( "&File", fileMenu );
    fileNewAction->addTo( fileMenu );
    fileOpenAction->addTo( fileMenu );
    fileSaveAction->addTo( fileMenu );
    fileSaveAsAction->addTo( fileMenu );
    fileMenu->insertSeparator();
    fileSaveAsPixmapAction->addTo( fileMenu );
    fileMenu->insertSeparator();
    filePrintAction->addTo( fileMenu );
    fileMenu->insertSeparator();
    fileQuitAction->addTo( fileMenu );
    fileMenu->insertSeparator();

    optionsMenu = new QPopupMenu( this );
    menuBar()->insertItem( "&Options", optionsMenu );
    optionsSetDataAction->addTo( optionsMenu );
    optionsMenu->insertSeparator();
    optionsPieChartAction->addTo( optionsMenu );
    optionsHorizontalBarChartAction->addTo( optionsMenu );
    optionsVerticalBarChartAction->addTo( optionsMenu );
    optionsMenu->insertSeparator();
    optionsSetFontAction->addTo( optionsMenu );
    optionsMenu->insertSeparator();
    optionsSetOptionsAction->addTo( optionsMenu );

    menuBar()->insertSeparator();

    QPopupMenu *helpMenu = new QPopupMenu( this );
    menuBar()->insertItem( "&Help", helpMenu );
    helpMenu->insertItem( "&Help", this, SLOT(helpHelp()), Key_F1 );
    helpMenu->insertItem( "&About", this, SLOT(helpAbout()) );
    helpMenu->insertItem( "About &Qt", this, SLOT(helpAboutQt()) );

    m_printer = 0;
    m_elements.resize( MAX_ELEMENTS );

    QSettings settings;
    settings.insertSearchPath( QSettings::Windows, WINDOWS_REGISTRY );
    int windowWidth = settings.readNumEntry( APP_KEY + "WindowWidth", 460 );
    int windowHeight = settings.readNumEntry( APP_KEY + "WindowHeight", 530 );
    int windowX = settings.readNumEntry( APP_KEY + "WindowX", 0 );
    int windowY = settings.readNumEntry( APP_KEY + "WindowY", 0 );
    setChartType( ChartType(
            settings.readNumEntry( APP_KEY + "ChartType", int(PIE) ) ) );
    m_addValues = AddValuesType(
                    settings.readNumEntry( APP_KEY + "AddValues", int(NO) ));
    m_decimalPlaces = settings.readNumEntry( APP_KEY + "Decimals", 2 );
    m_font = QFont( "Helvetica", 18, QFont::Bold );
    m_font.fromString(
            settings.readEntry( APP_KEY + "Font", m_font.toString() ) );
    for ( int i = 0; i < MAX_RECENTFILES; ++i ) {
        QString filename = settings.readEntry( APP_KEY + "File" +
                                               QString::number( i + 1 ) );
        if ( !filename.isEmpty() )
            m_recentFiles.push_back( filename );
    }
    if ( m_recentFiles.count() )
        updateRecentFilesMenu();

    // Connect *after* we've set the chart type on so we don't call
    // drawElements() prematurely.
    connect( chartGroup, SIGNAL( selected(QAction*) ),
             this, SLOT( updateChartType(QAction*) ) );

    resize( windowWidth, windowHeight );
    move( windowX, windowY );

    m_canvas = new QCanvas( this );
    m_canvas->resize( width(), height() );
    m_canvasView = new CanvasView( m_canvas, &m_elements, this );
    setCentralWidget( m_canvasView );
    m_canvasView->show();

    if ( !filename.isEmpty() )
        load( filename );
    else {
        init();
        m_elements[0].set( 20, red,    14, "Red" );
        m_elements[1].set( 70, cyan,    2, "Cyan",   darkGreen );
        m_elements[2].set( 35, blue,   11, "Blue" );
        m_elements[3].set( 55, yellow,  1, "Yellow", darkBlue );
        m_elements[4].set( 80, magenta, 1, "Magenta" );
        drawElements();
    }

    statusBar()->message( "Ready", 2000 );
}

ChartForm::~ChartForm()
{
    delete m_printer;
}

void ChartForm::init()
{
    setCaption( "Chart" );
    m_filename = QString::null;
    m_changed = false;

    m_elements[0]  = Element( Element::INVALID, red );
    m_elements[1]  = Element( Element::INVALID, cyan );
    m_elements[2]  = Element( Element::INVALID, blue );
    m_elements[3]  = Element( Element::INVALID, yellow );
    m_elements[4]  = Element( Element::INVALID, green );
    m_elements[5]  = Element( Element::INVALID, magenta );
    m_elements[6]  = Element( Element::INVALID, darkYellow );
    m_elements[7]  = Element( Element::INVALID, darkRed );
    m_elements[8]  = Element( Element::INVALID, darkCyan );
    m_elements[9]  = Element( Element::INVALID, darkGreen );
    m_elements[10] = Element( Element::INVALID, darkMagenta );
    m_elements[11] = Element( Element::INVALID, darkBlue );
    for ( int i = 12; i < MAX_ELEMENTS; ++i ) {
        double x = (double(i) / MAX_ELEMENTS) * 360;
        int y = (int(x * 256) % 105) + 151;
        int z = ((i * 17) % 105) + 151;
        m_elements[i] = Element( Element::INVALID, QColor( int(x), y, z, QColor::Hsv ) );
    }
}

void ChartForm::fileNew()
{
    if ( okToClear() ) {
        init();
        drawElements();
    }
}

void ChartForm::fileOpen()
{
    if ( !okToClear() )
        return;

    QString filename = QFileDialog::getOpenFileName(
                            QString::null, "Charts (*.cht)", this,
                            "file open", "Chart -- File Open" );
    if ( !filename.isEmpty() )
        load( filename );
    else
        statusBar()->message( "File Open abandoned", 2000 );
}

void ChartForm::fileSaveAs()
{
    QString filename = QFileDialog::getSaveFileName(
                            QString::null, "Charts (*.cht)", this,
                            "file save as", "Chart -- File Save As" );
    if ( !filename.isEmpty() ) {
        int answer = 0;
        if ( QFile::exists( filename ) )
            answer = QMessageBox::warning(
                            this, "Chart -- Overwrite File",
                            QString( "Overwrite\n\'%1\'?" ).
                                arg( filename ),
                            "&Yes", "&No", QString::null, 1, 1 );
        if ( answer == 0 ) {
            m_filename = filename;
            updateRecentFiles( filename );
            fileSave();
            return;
        }
    }
    statusBar()->message( "Saving abandoned", 2000 );
}

void ChartForm::fileOpenRecent( int index )
{
    if ( !okToClear() )
        return;

    load( m_recentFiles[index] );
}

void ChartForm::updateRecentFiles( const QString& filename )
{
    if ( m_recentFiles.find( filename ) != m_recentFiles.end() )
        return;

    m_recentFiles.push_back( filename );
    if ( m_recentFiles.count() > MAX_RECENTFILES )
        m_recentFiles.pop_front();

    updateRecentFilesMenu();
}

void ChartForm::updateRecentFilesMenu()
{
    for ( int i = 0; i < MAX_RECENTFILES; ++i ) {
        if ( fileMenu->findItem( i ) )
            fileMenu->removeItem( i );
        if ( i < int(m_recentFiles.count()) )
            fileMenu->insertItem( QString( "&%1 %2" ).
                                    arg( i + 1 ).arg( m_recentFiles[i] ),
                                  this, SLOT( fileOpenRecent(int) ),
                                  0, i );
    }
}

void ChartForm::fileQuit()
{
    if ( okToClear() ) {
        saveOptions();
        qApp->exit( 0 );
    }
}

bool ChartForm::okToClear()
{
    if ( m_changed ) {
        QString msg;
        if ( m_filename.isEmpty() )
            msg = "Unnamed chart ";
        else
            msg = QString( "Chart '%1'\n" ).arg( m_filename );
        msg += "has been changed.";
        switch( QMessageBox::information( this, "Chart -- Unsaved Changes",
                                          msg, "&Save", "Cancel", "&Abandon",
                                          0, 1 ) ) {
            case 0:
                fileSave();
                break;
            case 1:
            default:
                return false;
                break;
            case 2:
                break;
        }
    }

    return true;
}

void ChartForm::saveOptions()
{
    QSettings settings;
    settings.insertSearchPath( QSettings::Windows, WINDOWS_REGISTRY );
    settings.writeEntry( APP_KEY + "WindowWidth", width() );
    settings.writeEntry( APP_KEY + "WindowHeight", height() );
    settings.writeEntry( APP_KEY + "WindowX", x() );
    settings.writeEntry( APP_KEY + "WindowY", y() );
    settings.writeEntry( APP_KEY + "ChartType", int(m_chartType) );
    settings.writeEntry( APP_KEY + "AddValues", int(m_addValues) );
    settings.writeEntry( APP_KEY + "Decimals", m_decimalPlaces );
    settings.writeEntry( APP_KEY + "Font", m_font.toString() );
    for ( int i = 0; i < int(m_recentFiles.count()); ++i )
        settings.writeEntry( APP_KEY + "File" + QString::number( i + 1 ),
                             m_recentFiles[i] );
}

void ChartForm::optionsSetData()
{
    SetDataForm *setDataForm = new SetDataForm( &m_elements, m_decimalPlaces, this );
    if ( setDataForm->exec() ) {
        m_changed = true;
        drawElements();
    }
    delete setDataForm;
}

void ChartForm::setChartType( ChartType chartType )
{
    m_chartType = chartType;
    switch ( m_chartType ) {
        case PIE:
            optionsPieChartAction->setOn( true );
            break;
        case VERTICAL_BAR:
            optionsVerticalBarChartAction->setOn( true );
            break;
        case HORIZONTAL_BAR:
            optionsHorizontalBarChartAction->setOn( true );
            break;
    }
}

void ChartForm::updateChartType( QAction *action )
{
    if ( action == optionsPieChartAction ) {
        m_chartType = PIE;
    }
    else if ( action == optionsHorizontalBarChartAction ) {
        m_chartType = HORIZONTAL_BAR;
    }
    else if ( action == optionsVerticalBarChartAction ) {
        m_chartType = VERTICAL_BAR;
    }

    drawElements();
}

void ChartForm::optionsSetFont()
{
    bool ok;
    QFont font = QFontDialog::getFont( &ok, m_font, this );
    if ( ok ) {
        m_font = font;
        drawElements();
    }
}

void ChartForm::optionsSetOptions()
{
    OptionsForm *optionsForm = new OptionsForm( this );
    optionsForm->chartTypeComboBox->setCurrentItem( m_chartType );
    optionsForm->setFont( m_font );
    switch ( m_addValues ) {
        case NO:
            optionsForm->noRadioButton->setChecked( true );
            break;
        case YES:
            optionsForm->yesRadioButton->setChecked( true );
            break;
        case AS_PERCENTAGE:
            optionsForm->asPercentageRadioButton->setChecked( true );
            break;
    }
    optionsForm->decimalPlacesSpinBox->setValue( m_decimalPlaces );
    if ( optionsForm->exec() ) {
        setChartType( ChartType(
                optionsForm->chartTypeComboBox->currentItem()) );
        m_font = optionsForm->font();
        if ( optionsForm->noRadioButton->isChecked() )
            m_addValues = NO;
        else if ( optionsForm->yesRadioButton->isChecked() )
            m_addValues = YES;
        else if ( optionsForm->asPercentageRadioButton->isChecked() )
            m_addValues = AS_PERCENTAGE;
        m_decimalPlaces = optionsForm->decimalPlacesSpinBox->value();
        drawElements();
    }
    delete optionsForm;
}

void ChartForm::helpHelp()
{
    statusBar()->message( "Help is not implemented yet", 2000 );
}

void ChartForm::helpAbout()
{
    QMessageBox::about( this, "Chart -- About",
                        "<center><h1><font color=blue>Chart<font></h1></center>"
                        "<p>Chart your data with <i>chart</i>.</p>"
                        );
}

void ChartForm::helpAboutQt()
{
    QMessageBox::aboutQt( this, "Chart -- About Qt" );
}

 Main:

#include <qapplication.h>
#include "chartform.h"

int main( int argc, char *argv[] )
{
    QApplication app( argc, argv );

    QString filename;
    if ( app.argc() > 1 ) {
        filename = app.argv()[1];
        if ( !filename.endsWith( ".cht" ) )
            filename = QString::null;
    }

    ChartForm *cf = new ChartForm( filename );
    app.setMainWidget( cf );
    cf->show();
    app.connect( &app, SIGNAL(lastWindowClosed()), cf, SLOT(fileQuit()) );

    return app.exec();
}

See also Step-by-step Examples.

Copyright © 2002
TrolltechTrademarks

Qt version 3.0.5


Canvas Example

This example shows a QCanvas and some QCanvasItems in action. You can do a lot more with QCanvas than we show here, but the example provides a taste of what can be done.

Header file:

#ifndef EXAMPLE_H
#define EXAMPLE_H

#include <qpopupmenu.h>
#include <qmainwindow.h>
#include <qintdict.h>
#include <qcanvas.h>

class BouncyLogo : public QCanvasSprite {
    void initPos();
    void initSpeed();
public:
    BouncyLogo(QCanvas*);
    void advance(int);
    int rtti() const;
};

class FigureEditor : public QCanvasView {
    Q_OBJECT

public:
    FigureEditor(QCanvas&, QWidget* parent=0, const char* name=0, WFlags f=0);
    void clear();

protected:
    void contentsMousePressEvent(QMouseEvent*);
    void contentsMouseMoveEvent(QMouseEvent*);

signals:
    void status(const QString&);

private:
    QCanvasItem* moving;
    QPoint moving_start;
};

class Main : public QMainWindow {
    Q_OBJECT

public:
    Main(QCanvas&, QWidget* parent=0, const char* name=0, WFlags f=0);
    ~Main();

public slots:
    void help();

private slots:
    void aboutQt();
    void newView();
    void clear();
    void init();

    void addSprite();
    void addCircle();
    void addHexagon();
    void addPolygon();
    void addSpline();
    void addText();
    void addLine();
    void addRectangle();
    void addMesh();
    void addLogo();
    void addButterfly();

    void enlarge();
    void shrink();
    void rotateClockwise();
    void rotateCounterClockwise();
    void zoomIn();
    void zoomOut();
    void mirror();
    void moveL();
    void moveR();
    void moveU();
    void moveD();

    void print();

    void toggleDoubleBuffer();

private:
    QCanvas& canvas;
    FigureEditor *editor;

    QPopupMenu* options;
    QPrinter* printer;
    int dbf_id;
};

#endif

Implementation:

#include <qdatetime.h>
#include <qmainwindow.h>
#include <qstatusbar.h>
#include <qmessagebox.h>
#include <qmenubar.h>
#include <qapplication.h>
#include <qpainter.h>
#include <qprinter.h>
#include <qlabel.h>
#include <qimage.h>
#include <qprogressdialog.h>
#include "canvas.h"

#include <stdlib.h>

// We use a global variable to save memory - all the brushes and pens in
// the mesh are shared.
static QBrush *tb = 0;
static QPen *tp = 0;

class EdgeItem;
class NodeItem;

class EdgeItem: public QCanvasLine
{
public:
    EdgeItem( NodeItem*, NodeItem*, QCanvas *canvas );
    void setFromPoint( int x, int y ) ;
    void setToPoint( int x, int y );
    static int count() { return c; }
    void moveBy(double dx, double dy);
private:
    static int c;
};

static const int imageRTTI = 984376;

class ImageItem: public QCanvasRectangle
{
public:
    ImageItem( QImage img, QCanvas *canvas );
    int rtti () const { return imageRTTI; }
    bool hit( const QPoint&) const;
protected:
    void drawShape( QPainter & );
private:
    QImage image;
    QPixmap pixmap;
};

ImageItem::ImageItem( QImage img, QCanvas *canvas )
    : QCanvasRectangle( canvas ), image(img)
{
    setSize( image.width(), image.height() );

#if !defined(Q_WS_QWS)
    pixmap.convertFromImage(image, OrderedAlphaDither);
#endif
}

void ImageItem::drawShape( QPainter &p )
{
// On Qt/Embedded, we can paint a QImage as fast as a QPixmap,
// but on other platforms, we need to use a QPixmap.
#if defined(Q_WS_QWS)
    p.drawImage( int(x()), int(y()), image, 0, 0, -1, -1, OrderedAlphaDither );
#else
    p.drawPixmap( int(x()), int(y()), pixmap );
#endif
}

bool ImageItem::hit( const QPoint &p ) const
{
    int ix = p.x()-int(x());
    int iy = p.y()-int(y());
    if ( !image.valid( ix , iy ) )
        return FALSE;
    QRgb pixel = image.pixel( ix, iy );
    return qAlpha( pixel ) != 0;
}

class NodeItem: public QCanvasEllipse
{
public:
    NodeItem( QCanvas *canvas );
    ~NodeItem() {}

    void addInEdge( EdgeItem *edge ) { inList.append( edge ); }
    void addOutEdge( EdgeItem *edge ) { outList.append( edge ); }

    void moveBy(double dx, double dy);

    //    QPoint center() { return boundingRect().center(); }
private:
    QPtrList<EdgeItem> inList;
    QPtrList<EdgeItem> outList;
};

int EdgeItem::c = 0;

void EdgeItem::moveBy(double, double)
{
    //nothing
}

EdgeItem::EdgeItem( NodeItem *from, NodeItem *to, QCanvas *canvas )
    : QCanvasLine( canvas )
{
    c++;
    setPen( *tp );
    setBrush( *tb );
    from->addOutEdge( this );
    to->addInEdge( this );
    setPoints( int(from->x()), int(from->y()), int(to->x()), int(to->y()) );
    setZ( 127 );
}

void EdgeItem::setFromPoint( int x, int y )
{
    setPoints( x,y, endPoint().x(), endPoint().y() );
}

void EdgeItem::setToPoint( int x, int y )
{
    setPoints( startPoint().x(), startPoint().y(), x, y );
}

void NodeItem::moveBy(double dx, double dy)
{
    QCanvasEllipse::moveBy( dx, dy );

    QPtrListIterator<EdgeItem> it1( inList );
    EdgeItem *edge;
    while (( edge = it1.current() )) {
        ++it1;
        edge->setToPoint( int(x()), int(y()) );
    }
    QPtrListIterator<EdgeItem> it2( outList );
    while (( edge = it2.current() )) {
        ++it2;
        edge->setFromPoint( int(x()), int(y()) );
    }
}

NodeItem::NodeItem( QCanvas *canvas )
    : QCanvasEllipse( 6, 6, canvas )
{
    setPen( *tp );
    setBrush( *tb );
    setZ( 128 );
}

FigureEditor::FigureEditor(
        QCanvas& c, QWidget* parent,
        const char* name, WFlags f) :
    QCanvasView(&c,parent,name,f)
{
}

void FigureEditor::contentsMousePressEvent(QMouseEvent* e)
{
    QPoint p = inverseWorldMatrix().map(e->pos());
    QCanvasItemList l=canvas()->collisions(p);
    for (QCanvasItemList::Iterator it=l.begin(); it!=l.end(); ++it) {
        if ( (*it)->rtti() == imageRTTI ) {
            ImageItem *item= (ImageItem*)(*it);
            if ( !item->hit( p ) )
                 continue;
        }
        moving = *it;
        moving_start = p;
        return;
    }
    moving = 0;
}

void FigureEditor::clear()
{
    QCanvasItemList list = canvas()->allItems();
    QCanvasItemList::Iterator it = list.begin();
    for (; it != list.end(); ++it) {
        if ( *it )
            delete *it;
    }
}

void FigureEditor::contentsMouseMoveEvent(QMouseEvent* e)
{
    if ( moving ) {
        QPoint p = inverseWorldMatrix().map(e->pos());
        moving->moveBy(p.x() - moving_start.x(),
                       p.y() - moving_start.y());
        moving_start = p;
        canvas()->update();
    }
}

BouncyLogo::BouncyLogo(QCanvas* canvas) :
    QCanvasSprite(0,canvas)
{
    static QCanvasPixmapArray logo("qt-trans.xpm");
    setSequence(&logo);
    setAnimated(TRUE);
    initPos();
}

const int logo_rtti = 1234;

int BouncyLogo::rtti() const
{
    return logo_rtti;
}

void BouncyLogo::initPos()
{
    initSpeed();
    int trial=1000;
    do {
        move(rand()%canvas()->width(),rand()%canvas()->height());
        advance(0);
    } while (trial-- && xVelocity()==0.0 && yVelocity()==0.0);
}

void BouncyLogo::initSpeed()
{
    const double speed = 4.0;
    double d = (double)(rand()%1024) / 1024.0;
    setVelocity( d*speed*2-speed, (1-d)*speed*2-speed );
}

void BouncyLogo::advance(int stage)
{
    switch ( stage ) {
      case 0: {
        double vx = xVelocity();
        double vy = yVelocity();

        if ( vx == 0.0 && vy == 0.0 ) {
            // stopped last turn
            initSpeed();
            vx = xVelocity();
            vy = yVelocity();
        }

        double nx = x() + vx;
        double ny = y() + vy;

        if ( nx < 0 || nx >= canvas()->width() )
            vx = -vx;
        if ( ny < 0 || ny >= canvas()->height() )
            vy = -vy;

        for (int bounce=0; bounce<4; bounce++) {
            QCanvasItemList l=collisions(FALSE);
            for (QCanvasItemList::Iterator it=l.begin(); it!=l.end(); ++it) {
                QCanvasItem *hit = *it;
                if ( hit->rtti()==logo_rtti && hit->collidesWith(this) ) {
                    switch ( bounce ) {
                      case 0:
                        vx = -vx;
                        break;
                      case 1:
                        vy = -vy;
                        vx = -vx;
                        break;
                      case 2:
                        vx = -vx;
                        break;
                      case 3:
                        // Stop for this turn
                        vx = 0;
                        vy = 0;
                        break;
                    }
                    setVelocity(vx,vy);
                    break;
                }
            }
        }

        if ( x()+vx < 0 || x()+vx >= canvas()->width() )
            vx = 0;
        if ( y()+vy < 0 || y()+vy >= canvas()->height() )
            vy = 0;

        setVelocity(vx,vy);
      } break;
      case 1:
        QCanvasItem::advance(stage);
        break;
    }
}

static uint mainCount = 0;
static QImage *butterflyimg;
static QImage *logoimg;

Main::Main(QCanvas& c, QWidget* parent, const char* name, WFlags f) :
    QMainWindow(parent,name,f),
    canvas(c)
{
    editor = new FigureEditor(canvas,this);
    QMenuBar* menu = menuBar();

    QPopupMenu* file = new QPopupMenu( menu );
    file->insertItem("&Fill canvas", this, SLOT(init()), CTRL+Key_F);
    file->insertItem("&Erase canvas", this, SLOT(clear()), CTRL+Key_E);
    file->insertItem("&New view", this, SLOT(newView()), CTRL+Key_N);
    file->insertSeparator();
    file->insertItem("&Print", this, SLOT(print()), CTRL+Key_P);
    file->insertSeparator();
    file->insertItem("E&xit", qApp, SLOT(quit()), CTRL+Key_Q);
    menu->insertItem("&File", file);

    QPopupMenu* edit = new QPopupMenu( menu );
    edit->insertItem("Add &Circle", this, SLOT(addCircle()), ALT+Key_C);
    edit->insertItem("Add &Hexagon", this, SLOT(addHexagon()), ALT+Key_H);
    edit->insertItem("Add &Polygon", this, SLOT(addPolygon()), ALT+Key_P);
    edit->insertItem("Add Spl&ine", this, SLOT(addSpline()), ALT+Key_I);
    edit->insertItem("Add &Text", this, SLOT(addText()), ALT+Key_T);
    edit->insertItem("Add &Line", this, SLOT(addLine()), ALT+Key_L);
    edit->insertItem("Add &Rectangle", this, SLOT(addRectangle()), ALT+Key_R);
    edit->insertItem("Add &Sprite", this, SLOT(addSprite()), ALT+Key_S);
    edit->insertItem("Create &Mesh", this, SLOT(addMesh()), ALT+Key_M );
    edit->insertItem("Add &Alpha-blended image", this, SLOT(addButterfly()), ALT+Key_A);
    menu->insertItem("&Edit", edit);

    QPopupMenu* view = new QPopupMenu( menu );
    view->insertItem("&Enlarge", this, SLOT(enlarge()), SHIFT+CTRL+Key_Plus);
    view->insertItem("Shr&ink", this, SLOT(shrink()), SHIFT+CTRL+Key_Minus);
    view->insertSeparator();
    view->insertItem("&Rotate clockwise", this, SLOT(rotateClockwise()), CTRL+Key_PageDown);
    view->insertItem("Rotate &counterclockwise", this, SLOT(rotateCounterClockwise()), CTRL+Key_PageUp);
    view->insertItem("&Zoom in", this, SLOT(zoomIn()), CTRL+Key_Plus);
    view->insertItem("Zoom &out", this, SLOT(zoomOut()), CTRL+Key_Minus);
    view->insertItem("Translate left", this, SLOT(moveL()), CTRL+Key_Left);
    view->insertItem("Translate right", this, SLOT(moveR()), CTRL+Key_Right);
    view->insertItem("Translate up", this, SLOT(moveU()), CTRL+Key_Up);
    view->insertItem("Translate down", this, SLOT(moveD()), CTRL+Key_Down);
    view->insertItem("&Mirror", this, SLOT(mirror()), CTRL+Key_Home);
    menu->insertItem("&View", view);

    options = new QPopupMenu( menu );
    dbf_id = options->insertItem("Double buffer", this, SLOT(toggleDoubleBuffer()));
    options->setItemChecked(dbf_id, TRUE);
    menu->insertItem("&Options",options);

    menu->insertSeparator();

    QPopupMenu* help = new QPopupMenu( menu );
    help->insertItem("&About", this, SLOT(help()), Key_F1);
    help->setItemChecked(dbf_id, TRUE);
    menu->insertItem("&Help",help);

    statusBar();

    setCentralWidget(editor);

    printer = 0;

    init();
}

void Main::init()
{
    clear();

    static int r=24;
    srand(++r);

    mainCount++;
    butterflyimg = 0;
    logoimg = 0;

    int i;
    for ( i=0; i<canvas.width() / 56; i++) {
        addButterfly();
    }
    for ( i=0; i<canvas.width() / 85; i++) {
        addHexagon();
    }
    for ( i=0; i<canvas.width() / 128; i++) {
        addLogo();
    }
}

Main::~Main()
{
    delete printer;
    if ( !--mainCount ) {
        delete[] butterflyimg;
        butterflyimg = 0;
        delete[] logoimg;
        logoimg = 0;
    }
}

void Main::newView()
{
    // Open a new view... have it delete when closed.
    Main *m = new Main(canvas, 0, 0, WDestructiveClose);
    qApp->setMainWidget(m);
    m->show();
    qApp->setMainWidget(0);
}

void Main::clear()
{
    editor->clear();
}

void Main::help()
{
    static QMessageBox* about = new QMessageBox( "Qt Canvas Example",
            "<h3>The QCanvas classes example</h3>"
            "<ul>"
                "<li> Press ALT-S for some sprites."
                "<li> Press ALT-C for some circles."
                "<li> Press ALT-L for some lines."
                "<li> Drag the objects around."
                "<li> Read the code!"
            "</ul>", QMessageBox::Information, 1, 0, 0, this, 0, FALSE );
    about->setButtonText( 1, "Dismiss" );
    about->show();
}

void Main::aboutQt()
{
    QMessageBox::aboutQt( this, "Qt Canvas Example" );
}

void Main::toggleDoubleBuffer()
{
    bool s = !options->isItemChecked(dbf_id);
    options->setItemChecked(dbf_id,s);
    canvas.setDoubleBuffering(s);
}

void Main::enlarge()
{
    canvas.resize(canvas.width()*4/3, canvas.height()*4/3);
}

void Main::shrink()
{
    canvas.resize(canvas.width()*3/4, canvas.height()*3/4);
}

void Main::rotateClockwise()
{
    QWMatrix m = editor->worldMatrix();
    m.rotate( 22.5 );
    editor->setWorldMatrix( m );
}

void Main::rotateCounterClockwise()
{
    QWMatrix m = editor->worldMatrix();
    m.rotate( -22.5 );
    editor->setWorldMatrix( m );
}

void Main::zoomIn()
{
    QWMatrix m = editor->worldMatrix();
    m.scale( 2.0, 2.0 );
    editor->setWorldMatrix( m );
}

void Main::zoomOut()
{
    QWMatrix m = editor->worldMatrix();
    m.scale( 0.5, 0.5 );
    editor->setWorldMatrix( m );
}

void Main::mirror()
{
    QWMatrix m = editor->worldMatrix();
    m.scale( -1, 1 );
    editor->setWorldMatrix( m );
}

void Main::moveL()
{
    QWMatrix m = editor->worldMatrix();
    m.translate( -16, 0 );
    editor->setWorldMatrix( m );
}

void Main::moveR()
{
    QWMatrix m = editor->worldMatrix();
    m.translate( +16, 0 );
    editor->setWorldMatrix( m );
}

void Main::moveU()
{
    QWMatrix m = editor->worldMatrix();
    m.translate( 0, -16 );
    editor->setWorldMatrix( m );
}

void Main::moveD()
{
    QWMatrix m = editor->worldMatrix();
    m.translate( 0, +16 );
    editor->setWorldMatrix( m );
}

void Main::print()
{
    if ( !printer ) printer = new QPrinter;
    if ( printer->setup(this) ) {
        QPainter pp(printer);
        canvas.drawArea(QRect(0,0,canvas.width(),canvas.height()),&pp,FALSE);
    }
}

void Main::addSprite()
{
    QCanvasItem* i = new BouncyLogo(&canvas);
    i->setZ(rand()%256);
    i->show();
}

QString butterfly_fn;
QString logo_fn;

void Main::addButterfly()
{
    if ( butterfly_fn.isEmpty() )
        return;
    if ( !butterflyimg ) {
        butterflyimg = new QImage[4];
        butterflyimg[0].load( butterfly_fn );
        butterflyimg[1] = butterflyimg[0].smoothScale( int(butterflyimg[0].width()*0.75),
                int(butterflyimg[0].height()*0.75) );
        butterflyimg[2] = butterflyimg[0].smoothScale( int(butterflyimg[0].width()*0.5),
                int(butterflyimg[0].height()*0.5) );
        butterflyimg[3] = butterflyimg[0].smoothScale( int(butterflyimg[0].width()*0.25),
                int(butterflyimg[0].height()*0.25) );
    }
    QCanvasPolygonalItem* i = new ImageItem(butterflyimg[rand()%4],&canvas);
    i->move(rand()%(canvas.width()-butterflyimg->width()),
            rand()%(canvas.height()-butterflyimg->height()));
    i->setZ(rand()%256+250);
    i->show();
}

void Main::addLogo()
{
    if ( logo_fn.isEmpty() )
        return;
    if ( !logoimg ) {
        logoimg = new QImage[4];
        logoimg[0].load( logo_fn );
        logoimg[1] = logoimg[0].smoothScale( int(logoimg[0].width()*0.75),
                int(logoimg[0].height()*0.75) );
        logoimg[2] = logoimg[0].smoothScale( int(logoimg[0].width()*0.5),
                int(logoimg[0].height()*0.5) );
        logoimg[3] = logoimg[0].smoothScale( int(logoimg[0].width()*0.25),
                int(logoimg[0].height()*0.25) );
    }
    QCanvasPolygonalItem* i = new ImageItem(logoimg[rand()%4],&canvas);
    i->move(rand()%(canvas.width()-logoimg->width()),
            rand()%(canvas.height()-logoimg->width()));
    i->setZ(rand()%256+256);
    i->show();
}

void Main::addCircle()
{
    QCanvasPolygonalItem* i = new QCanvasEllipse(50,50,&canvas);
    i->setBrush( QColor(rand()%32*8,rand()%32*8,rand()%32*8) );
    i->move(rand()%canvas.width(),rand()%canvas.height());
    i->setZ(rand()%256);
    i->show();
}

void Main::addHexagon()
{
    QCanvasPolygon* i = new QCanvasPolygon(&canvas);
    const int size = canvas.width() / 25;
    QPointArray pa(6);
    pa[0] = QPoint(2*size,0);
    pa[1] = QPoint(size,-size*173/100);
    pa[2] = QPoint(-size,-size*173/100);
    pa[3] = QPoint(-2*size,0);
    pa[4] = QPoint(-size,size*173/100);
    pa[5] = QPoint(size,size*173/100);
    i->setPoints(pa);
    i->setBrush( QColor(rand()%32*8,rand()%32*8,rand()%32*8) );
    i->move(rand()%canvas.width(),rand()%canvas.height());
    i->setZ(rand()%256);
    i->show();
}

void Main::addPolygon()
{
    QCanvasPolygon* i = new QCanvasPolygon(&canvas);
    const int size = canvas.width()/2;
    QPointArray pa(6);
    pa[0] = QPoint(0,0);
    pa[1] = QPoint(size,size/5);
    pa[2] = QPoint(size*4/5,size);
    pa[3] = QPoint(size/6,size*5/4);
    pa[4] = QPoint(size*3/4,size*3/4);
    pa[5] = QPoint(size*3/4,size/4);
    i->setPoints(pa);
    i->setBrush( QColor(rand()%32*8,rand()%32*8,rand()%32*8) );
    i->move(rand()%canvas.width(),rand()%canvas.height());
    i->setZ(rand()%256);
    i->show();
}

void Main::addSpline()
{
    QCanvasSpline* i = new QCanvasSpline(&canvas);
    const int size = canvas.width()/6;
    QPointArray pa(12);
    pa[0] = QPoint(0,0);
    pa[1] = QPoint(size/2,0);
    pa[2] = QPoint(size,size/2);
    pa[3] = QPoint(size,size);
    pa[4] = QPoint(size,size*3/2);
    pa[5] = QPoint(size/2,size*2);
    pa[6] = QPoint(0,size*2);
    pa[7] = QPoint(-size/2,size*2);
    pa[8] = QPoint(size/4,size*3/2);
    pa[9] = QPoint(0,size);
    pa[10]= QPoint(-size/4,size/2);
    pa[11]= QPoint(-size/2,0);
    i->setControlPoints(pa);
    i->setBrush( QColor(rand()%32*8,rand()%32*8,rand()%32*8) );
    i->move(rand()%canvas.width(),rand()%canvas.height());
    i->setZ(rand()%256);
    i->show();
}

void Main::addText()
{
    QCanvasText* i = new QCanvasText(&canvas);
    i->setText("QCanvasText");
    i->move(rand()%canvas.width(),rand()%canvas.height());
    i->setZ(rand()%256);
    i->show();
}

void Main::addLine()
{
    QCanvasLine* i = new QCanvasLine(&canvas);
    i->setPoints( rand()%canvas.width(), rand()%canvas.height(),
                  rand()%canvas.width(), rand()%canvas.height() );
    i->setPen( QPen(QColor(rand()%32*8,rand()%32*8,rand()%32*8), 6) );
    i->setZ(rand()%256);
    i->show();
}

void Main::addMesh()
{
    int x0 = 0;
    int y0 = 0;

    if ( !tb ) tb = new QBrush( Qt::red );
    if ( !tp ) tp = new QPen( Qt::black );

    int nodecount = 0;

    int w = canvas.width();
    int h = canvas.height();

    const int dist = 30;
    int rows = h / dist;
    int cols = w / dist;

#ifndef QT_NO_PROGRESSDIALOG
    QProgressDialog progress( "Creating mesh...", "Abort", rows,
                              this, "progress", TRUE );
#endif

    QMemArray<NodeItem*> lastRow(cols);
    for ( int j = 0; j < rows; j++ ) {
        int n = j%2 ? cols-1 : cols;
        NodeItem *prev = 0;
        for ( int i = 0; i < n; i++ ) {
            NodeItem *el = new NodeItem( &canvas );
            nodecount++;
            int r = rand();
            int xrand = r %20;
            int yrand = (r/20) %20;
            el->move( xrand + x0 + i*dist + (j%2 ? dist/2 : 0 ),
                      yrand + y0 + j*dist );

            if ( j > 0 ) {
                if ( i < cols-1 )
                    (new EdgeItem( lastRow[i], el, &canvas ))->show();
                if ( j%2 )
                    (new EdgeItem( lastRow[i+1], el, &canvas ))->show();
                else if ( i > 0 )
                    (new EdgeItem( lastRow[i-1], el, &canvas ))->show();
            }
            if ( prev ) {
                (new EdgeItem( prev, el, &canvas ))->show();
            }
            if ( i > 0 ) lastRow[i-1] = prev;
            prev = el;
            el->show();
        }
        lastRow[n-1]=prev;
#ifndef QT_NO_PROGRESSDIALOG
        progress.setProgress( j );
        if ( progress.wasCancelled() )
            break;
#endif
    }
#ifndef QT_NO_PROGRESSDIALOG
    progress.setProgress( rows );
#endif
    // qDebug( "%d nodes, %d edges", nodecount, EdgeItem::count() );
}

void Main::addRectangle()
{
    QCanvasPolygonalItem *i = new QCanvasRectangle( rand()%canvas.width(),rand()%canvas.height(),
                            canvas.width()/5,canvas.width()/5,&canvas);
    int z = rand()%256;
    i->setBrush( QColor(z,z,z) );
    i->setPen( QPen(QColor(rand()%32*8,rand()%32*8,rand()%32*8), 6) );
    i->setZ(z);
    i->show();
}

Main:

#include <qstatusbar.h>
#include <qmessagebox.h>
#include <qmenubar.h>
#include <qapplication.h>
#include <qimage.h>

#include "canvas.h"

#include <stdlib.h>

extern QString butterfly_fn;
extern QString logo_fn;

int main(int argc, char** argv)
{
    QApplication app(argc,argv);

    /*
    qDebug("sizeof(QCanvasPolygonalItem)=%d",sizeof(QCanvasPolygonalItem));
    qDebug("sizeof(QCanvasText)=%d",sizeof(QCanvasText));
    qDebug("sizeof(QWidget)=%d",sizeof(QWidget));
    qDebug("sizeof(QLabel)=%d",sizeof(QLabel));
    */

    if ( argc > 1 )
        butterfly_fn = argv[1];
    else
        butterfly_fn = "butterfly.png";

    if ( argc > 2 )
        logo_fn = argv[2];
    else
        logo_fn = "qtlogo.png";

    QCanvas canvas(800,600);
    canvas.setAdvancePeriod(30);
    Main m(canvas);
    m.resize(m.sizeHint());

    qApp->setMainWidget(&m);

    m.setCaption("Qt Example - Canvas");
    if ( QApplication::desktop()->width() > m.width() + 10
         && QApplication::desktop()->height() > m.height() +30 )
        m.show();
    else
        m.showMaximized();

    m.show();
    //    m.help();
    qApp->setMainWidget(0);

    QObject::connect( qApp, SIGNAL(lastWindowClosed()), qApp, SLOT(quit()) );

    return app.exec();
}

See also Examples.


Listviews with Checkable Items

This example program shows how to use listviews with different types of checkable items.

Header file:

/****************************************************************************
** $Id:  qt/checklists.h   3.0.5   edited Oct 12 2001 $
**
** Copyright (C) 1992-2000 Trolltech AS.  All rights reserved.
**
** This file is part of an example program for Qt.  This example
** program may be used, distributed and modified without limitation.
**
*****************************************************************************/

#ifndef CHECKLISTS_H
#define CHECKLISTS_H

#include <qwidget.h>

class QListView;
class QLabel;

class CheckLists : public QWidget
{
    Q_OBJECT

public:
    CheckLists( QWidget *parent = 0, const char *name = 0 );

protected:
    QListView *lv1, *lv2;
    QLabel *label;

protected slots:
    void copy1to2();
    void copy2to3();

};

#endif

Implementation:

/****************************************************************************
** $Id:  qt/checklists.cpp   3.0.5   edited Oct 12 2001 $
**
** Copyright (C) 1992-2000 Trolltech AS.  All rights reserved.
**
** This file is part of an example program for Qt.  This example
** program may be used, distributed and modified without limitation.
**
*****************************************************************************/

#include "checklists.h"

#include <qlistview.h>
#include <qvbox.h>
#include <qlabel.h>
#include <qvaluelist.h>
#include <qstring.h>
#include <qpushbutton.h>
#include <qlayout.h>

/*
 * Constructor
 *
 * Create all child widgets of the CheckList Widget
 */

CheckLists::CheckLists( QWidget *parent, const char *name )
    : QWidget( parent, name )
{
    QHBoxLayout *lay = new QHBoxLayout( this );
    lay->setMargin( 5 );

    // create a widget which layouts its childs in a column
    QVBoxLayout *vbox1 = new QVBoxLayout( lay );
    vbox1->setMargin( 5 );

    // First child: a Label
    vbox1->addWidget( new QLabel( "Check some items!", this ) );

    // Second child: the ListView
    lv1 = new QListView( this );
    vbox1->addWidget( lv1 );
    lv1->addColumn( "Items" );
    lv1->setRootIsDecorated( TRUE );

    // create a list with 4 ListViewItems which will be parent items of other ListViewItems
    QValueList<QListViewItem *> parentList;

    parentList.append( new QListViewItem( lv1, "Parent Item 1" ) );
    parentList.append( new QListViewItem( lv1, "Parent Item 2" ) );
    parentList.append( new QListViewItem( lv1, "Parent Item 3" ) );
    parentList.append( new QListViewItem( lv1, "Parent Item 4" ) );

    QListViewItem *item = 0;
    unsigned int num = 1;
    // go through the list of parent items...
    for ( QValueList<QListViewItem*>::Iterator it = parentList.begin(); it != parentList.end();
          ( *it )->setOpen( TRUE ), ++it, num++ ) {
        item = *it;
        // ...and create 5 checkable child ListViewItems for each parent item
        for ( unsigned int i = 1; i <= 5; i++ )
            (void)new QCheckListItem( item, QString( "%1. Child of Parent %2" ).arg( i ).arg( num ), QCheckListItem::CheckBox );
    }

    // Create another widget for layouting
    QVBoxLayout *tmp = new QVBoxLayout( lay );
    tmp->setMargin( 5 );

    // create a pushbutton
    QPushButton *copy1 = new QPushButton( "  ->  ", this );
    tmp->addWidget( copy1 );
    copy1->setMaximumWidth( copy1->sizeHint().width() );
    // connect the SIGNAL clicked() of the pushbutton with the SLOT copy1to2()
    connect( copy1, SIGNAL( clicked() ), this, SLOT( copy1to2() ) );

    // another widget for layouting
    QVBoxLayout *vbox2 = new QVBoxLayout( lay );
    vbox2->setMargin( 5 );

    // and another label
    vbox2->addWidget( new QLabel( "Check one item!", this ) );

    // create the second listview
    lv2 = new QListView( this );
    vbox2->addWidget( lv2 );
    lv2->addColumn( "Items" );
    lv2->setRootIsDecorated( TRUE );

    // another widget needed for layouting only
    tmp = new QVBoxLayout( lay );
    tmp->setMargin( 5 );

    // create another pushbutton...
    QPushButton *copy2 = new QPushButton( "  ->  ", this );
    lay->addWidget( copy2 );
    copy2->setMaximumWidth( copy2->sizeHint().width() );
    // ...and connect its clicked() SIGNAL to the copy2to3() SLOT
    connect( copy2, SIGNAL( clicked() ), this, SLOT( copy2to3() ) );

    tmp = new QVBoxLayout( lay );
    tmp->setMargin( 5 );

    // and create a label which will be at the right of the window
    label = new QLabel( "No Item yet...", this );
    tmp->addWidget( label );
}

/*
 * SLOT copy1to2()
 *
 * Copies all checked ListViewItems from the first ListView to
 * the second one, and inserts them as Radio-ListViewItem.
 */

void CheckLists::copy1to2()
{
    // create an iterator which operates on the first ListView
    QListViewItemIterator it( lv1 );

    lv2->clear();

    // Insert first a controller Item into the second ListView. Always if Radio-ListViewItems
    // are inserted into a Listview, the parent item of these MUST be a controller Item!
    QCheckListItem *item = new QCheckListItem( lv2, "Controller", QCheckListItem::Controller );
    item->setOpen( TRUE );

    // iterate through the first ListView...
    for ( ; it.current(); ++it )
        // ...check state of childs, and...
        if ( it.current()->parent() )
            // ...if the item is checked...
            if ( ( (QCheckListItem*)it.current() )->isOn() )
                // ...insert a Radio-ListViewItem with the same text into the second ListView
                (void)new QCheckListItem( item, it.current()->text( 0 ), QCheckListItem::RadioButton );

    if ( item->firstChild() )
        ( ( QCheckListItem* )item->firstChild() )->setOn( TRUE );
}

/*
 * SLOT copy2to3()
 *
 * Copies the checked item of the second ListView into the
 * Label at the right.
 */

void CheckLists::copy2to3()
{
    // create an iterator which operates on the second ListView
    QListViewItemIterator it( lv2 );

    label->setText( "No Item checked" );

    // iterate through the second ListView...
    for ( ; it.current(); ++it )
        // ...check state of childs, and...
        if ( it.current()->parent() )
            // ...if the item is checked...
            if ( ( (QCheckListItem*)it.current() )->isOn() )
                // ...set the text of the item to the label
                label->setText( it.current()->text( 0 ) );
}

Main:

/****************************************************************************
** $Id:  qt/main.cpp   3.0.5   edited Oct 12 2001 $
**
** Copyright (C) 1992-2000 Trolltech AS.  All rights reserved.
**
** This file is part of an example program for Qt.  This example
** program may be used, distributed and modified without limitation.
**
*****************************************************************************/

#include "checklists.h"
#include <qapplication.h>

int main( int argc, char **argv )
{
    QApplication a( argc, argv );

    CheckLists checklists;
    checklists.resize( 650, 350 );
    checklists.setCaption( "Qt Example - CheckLists" );
    a.setMainWidget( &checklists );
    checklists.show();

    return a.exec();
}

See also Examples.


A small client-server example

This example shows how two programs can communicate using sockets.

Two simple example programs are provided, a client program and a server program. Both use the QSocket class, and the server also uses QServerSocket class.

The server listens on port number 4242 and accepts incoming connections. It sends back every line it receives from the client, prepended with the line number.

The client tries to connect to the server on the host specified on the command line or to localhost if no command line arguments are specified. You can send single lines to the server.

Implementation server (server.cpp):

/****************************************************************************
** $Id:  qt/server.cpp   3.0.5   edited Oct 12 2001 $
**
** Copyright (C) 1992-2000 Trolltech AS.  All rights reserved.
**
** This file is part of an example program for Qt.  This example
** program may be used, distributed and modified without limitation.
**
*****************************************************************************/

#include <qsocket.h>
#include <qserversocket.h>
#include <qapplication.h>
#include <qvbox.h>
#include <qtextview.h>
#include <qlabel.h>
#include <qpushbutton.h>
#include <qtextstream.h>

#include <stdlib.h>

/*
  The ClientSocket class provides a socket that is connected with a client.
  For every client that connects to the server, the server creates a new
  instance of this class.
*/
class ClientSocket : public QSocket
{
    Q_OBJECT
public:
    ClientSocket( int sock, QObject *parent=0, const char *name=0 ) :
        QSocket( parent, name )
    {
        line = 0;
        connect( this, SIGNAL(readyRead()), SLOT(readClient()) );
        connect( this, SIGNAL(connectionClosed()), SLOT(connectionClosed()) );
        setSocket( sock );
    }

    ~ClientSocket()
    {
    }

private slots:
    void readClient()
    {
        while ( canReadLine() ) {
            QTextStream os( this );
            os << line << ": " << readLine();
            line++;
        }
    }

    void connectionClosed()
    {
        delete this;
    }

private:
    int line;
};

/*
  The SimpleServer class handles new connections to the server. For every
  client that connects, it creates a new ClientSocket -- that instance is now
  responsible for the communication with that client.
*/
class SimpleServer : public QServerSocket
{
    Q_OBJECT
public:
    SimpleServer( QObject* parent=0 ) :
        QServerSocket( 4242, 1, parent )
    {
        if ( !ok() ) {
            qWarning("Failed to bind to port 4242");
            exit(1);
        }
    }

    ~SimpleServer()
    {
    }

    void newConnection( int socket )
    {
        (void)new ClientSocket( socket, this );
        emit newConnect();
    }

signals:
    void newConnect();
};

/*
  The ServerInfo class provides a small GUI for the server. It also creates the
  SimpleServer and as a result the server.
*/
class ServerInfo : public QVBox
{
    Q_OBJECT
public:
    ServerInfo()
    {
        SimpleServer *server = new SimpleServer( this );

        QString itext = QString(
                "This is a small server example.\n"
                "Connect with the client now."
                );
        QLabel *lb = new QLabel( itext, this );
        lb->setAlignment( AlignHCenter );
        infoText = new QTextView( this );
        QPushButton *quit = new QPushButton( "Quit" , this );

        connect( server, SIGNAL(newConnect()), SLOT(newConnect()) );
        connect( quit, SIGNAL(clicked()), qApp, SLOT(quit()) );
    }

    ~ServerInfo()
    {
    }

private slots:
    void newConnect()
    {
        infoText->append( "New connection\n" );
    }

private:
    QTextView *infoText;
};

int main( int argc, char** argv )
{
    QApplication app( argc, argv );
    ServerInfo info;
    app.setMainWidget( &info );
    info.show();
    return app.exec();
}

#include "server.moc"

Implementation client (client.cpp):

/****************************************************************************
** $Id:  qt/client.cpp   3.0.5   edited Nov 5 2001 $
**
** Copyright (C) 1992-2000 Trolltech AS.  All rights reserved.
**
** This file is part of an example program for Qt.  This example
** program may be used, distributed and modified without limitation.
**
*****************************************************************************/

#include <qsocket.h>
#include <qapplication.h>
#include <qvbox.h>
#include <qhbox.h>
#include <qtextview.h>
#include <qlineedit.h>
#include <qlabel.h>
#include <qpushbutton.h>
#include <qtextstream.h>

class Client : public QVBox
{
    Q_OBJECT
public:
    Client( const QString &host, Q_UINT16 port )
    {
        // GUI layout
        infoText = new QTextView( this );
        QHBox *hb = new QHBox( this );
        inputText = new QLineEdit( hb );
        QPushButton *send = new QPushButton( tr("Send") , hb );
        QPushButton *close = new QPushButton( tr("Close connection") , this );
        QPushButton *quit = new QPushButton( tr("Quit") , this );

        connect( send, SIGNAL(clicked()), SLOT(sendToServer()) );
        connect( close, SIGNAL(clicked()), SLOT(closeConnection()) );
        connect( quit, SIGNAL(clicked()), qApp, SLOT(quit()) );

        // create the socket and connect various of its signals
        socket = new QSocket( this );
        connect( socket, SIGNAL(connected()),
                SLOT(socketConnected()) );
        connect( socket, SIGNAL(connectionClosed()),
                SLOT(socketConnectionClosed()) );
        connect( socket, SIGNAL(readyRead()),
                SLOT(socketReadyRead()) );
        connect( socket, SIGNAL(error(int)),
                SLOT(socketError(int)) );

        // connect to the server
        infoText->append( tr("Trying to connect to the server\n") );
        socket->connectToHost( host, port );
    }

    ~Client()
    {
    }

private slots:
    void closeConnection()
    {
        socket->close();
        if ( socket->state() == QSocket::Closing ) {
            // We have a delayed close.
            connect( socket, SIGNAL(delayedCloseFinished()),
                    SLOT(socketClosed()) );
        } else {
            // The socket is closed.
            socketClosed();
        }
    }

    void sendToServer()
    {
        // write to the server
        QTextStream os(socket);
        os << inputText->text() << "\n";
        inputText->setText( "" );
    }

    void socketReadyRead()
    {
        // read from the server
        while ( socket->canReadLine() ) {
            infoText->append( socket->readLine() );
        }
    }

    void socketConnected()
    {
        infoText->append( tr("Connected to server\n") );
    }

    void socketConnectionClosed()
    {
        infoText->append( tr("Connection closed by the server\n") );
    }

    void socketClosed()
    {
        infoText->append( tr("Connection closed\n") );
    }

    void socketError( int e )
    {
        infoText->append( tr("Error number %1 occurred\n").arg(e) );
    }

private:
    QSocket *socket;
    QTextView *infoText;
    QLineEdit *inputText;
};

int main( int argc, char** argv )
{
    QApplication app( argc, argv );
    Client client( argc<2 ? "localhost" : argv[1], 4242 );
    app.setMainWidget( &client );
    client.show();
    return app.exec();
}

#include "client.moc"

See also Network Examples.


Collection Classes

A collection class is a container which holds a number of items in a certain data structure and performs operations on the contained items; insert, remove, find etc.

Qt has several value-based and several pointer-based collection classes. The pointer-based collection classes work with pointers to items, while the value-based classes store copies of their items. The value-based collections are very similar to STL container classes, and can be used with STL algorithms and containers. See the Qt Template Library documentation for details.

The value-based collections are:

  • QValueList, a value-based list
  • QValueVector, a value-based vector structure
  • QValueStack, a value-based stack structure
  • QMap, a value-based dictionary structure

The pointer-based collections are:

  • QCache and QIntCache, LRU (least recently used) cache structures.
  • QDict, QIntDict and QPtrDict dictionary structures.
  • QPtrList, a double linked list structure.
  • QPtrQueue, a FIFO (first in, first out) queue structure.
  • QPtrStack, a LIFO (last in, first out) stack structure.
  • QPtrVector, a vector structure.

QMemArray is exceptional; it is neither pointer nor value based, but memory based. For maximum efficiency with the simple data types usually used in arrays, it uses bitwise operations to copy and compare array elements.

Some of these classes have corresponding iterators. An iterator is a class for traversing the items in a collection:

  • QCacheIterator and QIntCacheIterator
  • QDictIterator, QIntDictIterator, and QPtrDictIterator
  • QPtrListIterator
  • QValueListIterator, and QValueListConstIterator
  • QMapIterator, and QMapConstIterator

The value-based collections plus algorithms operating on them are grouped together in the Qt Template Library. See the respective documentation for details.

The rest of this page dicusses the pointer-based containers.

Architecture of the pointer-based containers

There are four internal base classes for the pointer-based containers (QGCache, QGDict, QGList and QGVector) that operate on void pointers. A thin template layer implements the actual collections by casting item pointers to and from void pointers.

This strategy allows Qt's templates to be very economical on space (instantiating one of these templates adds only inlinable calls to the base classes), while it does not hurt performance.

A QPtrList Example

This example shows how to store Employee items in a list and prints them out in the reverse order:

    #include <qptrlist.h>
    #include <qstring.h>
    #include <stdio.h>

    class Employee
    {
    public:
        Employee( const char *name, int salary ) { n=name; s=salary; }
        const char *name()   const               { return n; }
        int         salary() const               { return s; }
    private:
        QString     n;
        int         s;
    };

    int main()
    {
        QPtrList<Employee> list;                // list of pointers to Employee
        list.setAutoDelete( TRUE );     // delete items when they are removed

        list.append( new Employee("Bill", 50000) );
        list.append( new Employee("Steve",80000) );
        list.append( new Employee("Ron",  60000) );

        QPtrListIterator<Employee> it(list); // iterator for employee list
        for ( it.toLast(); it.current(); --it) ) {
            Employee *emp = it.current();
            printf( "%s earns %d\n", emp->name(), emp->salary() );
        }

        return 0;
    }

Program output:

    Ron earns 60000
    Steve earns 80000
    Bill earns 50000

Managing Collection Items

All pointer-based collections inherit the QPtrCollection base class. This class knows only the number of items in the collection and the delete strategy.

Items in a collection are by default not deleted when they are removed from the collection. The QPtrCollection::setAutoDelete() function specifies the delete strategy. In the list example, we enable auto-deletion to make the list delete the items when they are removed from the list.

When inserting an item into a collection, only the pointer is copied, not the item itself. This is called a shallow copy. It is possible to make the collection copy all of the item's data (known as a deep copy) when an item is inserted. All collection functions that insert an item call the virtual function QPtrCollection::newItem() for the item to be inserted. Inherit a collection and reimplement it if you want to have deep copies in your collection.

When removing an item from a list, the virtual function QPtrCollection::deleteItem() is called. The default implementation in all collection classes deletes the item if auto-deletion is enabled.

Usage

A pointer-based collection class, such as QPtrList<type>, defines a collection of pointers to type objects. The pointer (*) is implicit.

We discuss QPtrList here, but the same techniques apply for all pointer-based collection classes and all collection class iterators.

Template instantiation:

    QPtrList<Employee> list;            // wherever the list is used

The item's class or type, Employee in our example, must be defined prior to the list definition.

    // Does not work: Employee is not defined
    class Employee;
    QPtrList<Employee> list;

    // This works: Employee is defined before it is used
    class Employee {
        ...
    };
    QPtrList<Employee> list;

Iterators

Although QPtrList has member functions to traverse the list, it can often be better to make use of an iterator. QPtrListIterator is very safe and can traverse lists that are being modified at the same time. Multiple iterators can work independently on the same collection.

A QPtrList has an internal list of all iterators that are currently operating on the list. When a list entry is removed, the list updates all iterators to point to this entry.

The QDict and QCache collections have no traversal functions. To traverse these collections, you must use QDictIterator or QCacheIterator.

Predefined Collections

Qt has the following predefined collection classes:

  • String lists: QStrList, QStrIList (qstrlist.h) and QStringList (qstringlist.h)
  • String vectors: QStrVec and QStrIVec (qstrvec.h); these are obsolete

In almost all cases you would choose QStringList, a value list of implicitly shared QString unicode strings. QPtrStrList and QPtrStrIList store only char pointers, not the strings themselves.

List of Pointer-based Collection Classes and Related Iterator Classes

QAsciiCache | Template class that provides a cache based on char* keys
QAsciiCacheIterator | Iterator for QAsciiCache collections
QAsciiDict | Template class that provides a dictionary based on char* keys
QAsciiDictIterator | Iterator for QAsciiDict collections
QBitArray | Array of bits
QBitVal | Internal class, used with QBitArray
QBuffer | I/O device that operates on a QByteArray
QByteArray | Array of bytes
QCache | Template class that provides a cache based on QString keys
QCacheIterator | Iterator for QCache collections
QCString | Abstraction of the classic C zero-terminated char array (char *)
QDict | Template class that provides a dictionary based on QString keys
QDictIterator | Iterator for QDict collections
QIntCache | Template class that provides a cache based on long keys
QIntCacheIterator | Iterator for QIntCache collections
QIntDict | Template class that provides a dictionary based on long keys
QIntDictIterator | Iterator for QIntDict collections
QObjectList | QPtrList of QObjects
QObjectListIt | Iterator for QObjectLists
QPtrCollection | The base class of most pointer-based Qt collections
QPtrDict | Template class that provides a dictionary based on void* keys
QPtrDictIterator | Iterator for QPtrDict collections
QPtrList | Template class that provides doubly-linked lists
QPtrListIterator | Iterator for QPtrList collections
QPtrQueue | Template class that provides a queue
QStrIList | Doubly-linked list of char* with case-insensitive comparison
QStrList | Doubly-linked list of char*


坐标系统

在Qt中的一个绘画设备是一个可画的二维平面。QWidget、QPixmap、QPicture和QPrinter都是绘画设备。QPainter是一个可以在上面画的对象。

一个绘画设备的默认坐标系统的原点在左上角。X轴由左向右增加，Y轴由上向下增加。对于基于像素的设备单位是像素，对于打印机是点。

一个例子

下面这个图显示了一个绘画设备的左上角的高度放大的部分。

这个矩形和线段是由下面的代码画出来的（在这个图中添加了网格）：

    void MyWidget::paintEvent( QPaintEvent * )
    {
        QPainter p( this );
        p.setPen( darkGray );
        p.drawRect( 1,2, 5,4 );
        p.setPen( lightGray );
        p.drawLine( 9,2, 7,7 );
    }

applies to all the relevant functions in QPainter. 请注意drawRect()所画的所有像素是在指定的大小之内（5*4像素）。这一点和其它工具包不同；Qt中你指定的大小包括你所要画的像素。这一点适用于所有QPainter中相关的函数。

相似的，drawLine()调用画了这个线段的两个端点，而不仅仅是一个。

这里是一些和坐标系统关系很近的类：

  • QPoint是坐标系统中的单个二维点。Qt中处理点的绝大多数函数都可以接受QPoint参数或者两个整数参数，比如QPainter::drawPoint()。

  • QSize是单个二维矢量。在内部，QPoint和QSize是一样的，但是一个点和一个大小不同，所以这两个类都存在。同样，绝大多数函数都可以接受一个QSize或者两个整数，比如QWidget::resize()。

  • QRect是一个二维的矩形。绝大多数函数都可以接受一个QRect或者四个整数，比如QWidget::setGeometry()。

  • QRegion是点的一个任意组合，包括所有通常的组合操作，例如QRegion::intersect()，并且一些常用的函数返回一个矩形的列表，这个矩形的列表的集合等于一个区域。QRegion被例如QPainter::setClipRegion()、QWidget::repaint()和QPaintEvent::region()使用。

  • QPainter是一个绘图的类。它可以用同样的代码在任何一个设备上绘画。设备中是存在差异的，QPrinter::newPage()是一个很好的例子，但QPainter可以对所有的设备按同一种方式工作。

  • QPaintDevice是一个QPainter可以在上面绘画的设备。这里有两种都基于像素的内部的设备，和两种外部设备，QPrinter和QPicture（它把QPainter的命令都记录在一个文件或者其它的QIODevice，然后再运行它们）。其它的设备都可以被定义。

变换

尽管Qt默认的坐标系统像我们上面描述的那样工作，QPainter也支持任意的变换。

这个变换引擎是一个三步的管道，和下面的Foley & Van Dam and the OpenGL Programming Guide两本书中的模型非常接近。参考那些深度的内容，这里我们给出了一个简单的概述和一个例子。

第一步使用通用变换矩阵。使用这个矩阵来定位你的模型中的对象。Qt提供了像QPainter::rotate()、QPainter::scale()、QPainter::translate()等等方法来操作这个矩阵。

QPainter::save()和QPainter::restore()存储和恢复这个矩阵。你也可以使用QWMatrix对象、QPainter::worldMatrix()和QPainter::setWorldMatrix()来存储和使用指定的矩阵。

第二步使用窗口。这个窗口在模式坐标上说明视图的边界。矩阵定位对象并且QPainter::setWindow()定位这个窗口，决定哪个坐标系统是可见的。（如果你有三维的经验，这个窗口通常是被三维投影出来的。）

第三步使用视口。视口也描述视图的边界，但是是在设备坐标上。视口和窗口描述的是同一个矩形，但是在不同的坐标系统中。

在屏幕上，默认的是你所画的通常合适的整个QWidget或者QPixmap。对于打印这个功能是非常重要的，因为只有很少的打印机可以在真个物理页面上打印。

所以每一个要画的对象被使用QPainter::worldMatrix()变换到模式坐标中，然后被QPainter::window()剪辑，最后被使用QPainter::viewport()定位到所画的设备上。

没有上述一个或两个步骤也是可能做到的。举例来说，比如你的目标是画一些按比例缩放的东西，然后使用QPainter::scale()来达到理想的效果。如果你使用一个大小固定的坐标系统，QPainter::setWindow()是最好的。等等。

这里是一个使用所有这三个机制的一个简单的例子：这个函数在aclock/aclock.cpp例子中画了一个钟表面板。我们建议你在读任何代码之前先编译和运行这个例子。尤其是，试着把这个窗口改变成不同的形状。

    void AnalogClock::drawClock( QPainter *paint )
    {
        paint->save();

首先，我们保存绘画工具的状态，这样的调用函数就保证了不会将要使用的变换干扰。

        paint->setWindow( -500,-500, 1000,1000 );

我们设置一个1000*1000、原点（0，0)在中间的窗口的模式坐标系统。

        QRect v = paint->viewport();
        int d = QMIN( v.width(), v.height() );

这个设备也许不是正方形的，但我们希望钟表是正方形的，所以我们找到它当前的视口并计算它最短的边。

        paint->setViewport( v.left() + (v.width()-d)/2,
                            v.top() + (v.height()-d)/2, d, d );

然后我们设置一个新的正方形视口，把它放在原来的中间。

现在我们做完了我们的视图。从这点上来看，当我们在（0，0）点周围画一个1000*1000的区域，我们所画的东西将会在适合输出设备的最大可能的正方形区域中显示出来。

是我们开始绘图的时候了。

        // time = QTime::currentTime();
        QPointArray pts;

因为我们在画一个钟表，所以我们需要知道时间。pts刚好是一个用来存储一些点的有用的变量。

接下来我们画三个块，一个是时针，一个是分针，最后一个是钟表面板自己。首先我们来画时针：

        paint->save();
        paint->rotate( 30*(time.hour()%12-3) + time.minute()/2 );

我们保存绘画工具，然后根据时针转动的方向旋转它。

        pts.setPoints( 4, -20,0,  0,-20, 300,0, 0,20 );
        paint->drawConvexPolygon( pts );

我们把pts设置为一个四点的多边形，好像时针就在三点钟，然后画上它。因为这个旋转，时针被画到正确的位置。

        paint->restore();

我们恢复被存储哦绘图工具，取消旋转。我们也可以通过调用rotate( -30 )，但是那样也许会导致旋转错误，所以使用save()和restore()是更好的方法。接下来，按大致相同哦方式画分针：

        paint->save();
        paint->rotate( (time.minute()-15)*6 );
        pts.setPoints( 4, -10,0, 0,-10, 400,0, 0,10 );
        paint->drawConvexPolygon( pts );
        paint->restore();

唯一的不同是如何计算要旋转的角度和多边形的形状。

要画的最后一部分就是钟表面板自己。

        for ( int i=0; i<12; i++ ) {
            paint->drawLine( 440,0, 460,0 );
            paint->rotate( 30 );
        }

十二个短的时针刻度之间的间隔是三十度。最后，绘图工具被旋转不是一个非常有用的方法，但是我们已经画完了，所以这也没什么。

        paint->restore();
    }

最后一行的函数是恢复绘图工具，这样绘图工具的调用者就不用担心我们所做的所有变换会影响它。

Copyright © 2002 Trolltech Trademarks 译者:Cavendish
Qt 3.0.5版


Cursors

This example shows how to set a mouse cursor for a widget.

Implementation:

/****************************************************************************
** $Id:  qt/cursor.cpp   3.0.5   edited Oct 12 2001 $
**
** Copyright (C) 1992-2000 Trolltech AS.  All rights reserved.
**
** This file is part of an example program for Qt.  This example
** program may be used, distributed and modified without limitation.
**
*****************************************************************************/

#include <qlabel.h>
#include <qbitmap.h>
#include <qapplication.h>
#include <qlayout.h>
#include <qcursor.h>

// cb_bits and cm_bits were generated by X bitmap program.

#define cb_width  32
#define cb_height 32

static unsigned char cb_bits[] = {              // cursor bitmap
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x0f, 0x00,
   0x00, 0x06, 0x30, 0x00, 0x80, 0x01, 0xc0, 0x00, 0x40, 0x00, 0x00, 0x01,
   0x20, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x04, 0x08, 0x3e, 0x3e, 0x08,
   0x08, 0x03, 0xe0, 0x08, 0xc4, 0x00, 0x00, 0x11, 0x04, 0x1e, 0x78, 0x10,
   0x02, 0x0c, 0x30, 0x20, 0x02, 0x40, 0x00, 0x20, 0x02, 0x40, 0x00, 0x20,
   0x02, 0x40, 0x00, 0x20, 0x02, 0x20, 0x04, 0x20, 0x02, 0x20, 0x04, 0x20,
   0x02, 0x10, 0x08, 0x20, 0x02, 0x08, 0x08, 0x20, 0x02, 0xf0, 0x07, 0x20,
   0x04, 0x00, 0x00, 0x10, 0x04, 0x00, 0x00, 0x10, 0x08, 0x00, 0xc0, 0x08,
   0x08, 0x3c, 0x30, 0x08, 0x10, 0xe6, 0x19, 0x04, 0x20, 0x00, 0x0f, 0x02,
   0x40, 0x00, 0x00, 0x01, 0x80, 0x01, 0xc0, 0x00, 0x00, 0x06, 0x30, 0x00,
   0x00, 0xf8, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00};

#define cm_width  32
#define cm_height 32

static unsigned char cm_bits[] = {              // cursor bitmap mask
   0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x1f, 0x00, 0x00, 0xfe, 0x3f, 0x00,
   0x80, 0x07, 0xf0, 0x00, 0xc0, 0x01, 0xc0, 0x01, 0x60, 0x00, 0x00, 0x03,
   0x30, 0x00, 0x00, 0x06, 0x18, 0x00, 0x00, 0x0c, 0x0c, 0x3e, 0x3e, 0x18,
   0x0e, 0x03, 0xe0, 0x18, 0xc6, 0x00, 0x00, 0x31, 0x07, 0x1e, 0x78, 0x30,
   0x03, 0x0c, 0x30, 0x60, 0x03, 0x40, 0x00, 0x60, 0x03, 0x40, 0x00, 0x60,
   0x03, 0x40, 0x00, 0x60, 0x03, 0x20, 0x04, 0x60, 0x03, 0x20, 0x04, 0x60,
   0x03, 0x10, 0x08, 0x60, 0x03, 0x08, 0x08, 0x60, 0x03, 0xf0, 0x07, 0x60,
   0x06, 0x00, 0x00, 0x30, 0x06, 0x00, 0x00, 0x30, 0x0c, 0x00, 0xc0, 0x18,
   0x0c, 0x3c, 0x30, 0x18, 0x18, 0xe6, 0x19, 0x0c, 0x30, 0x00, 0x0f, 0x06,
   0x60, 0x00, 0x00, 0x03, 0xc0, 0x01, 0xc0, 0x01, 0x80, 0x07, 0xf0, 0x00,
   0x00, 0xfe, 0x3f, 0x00, 0x00, 0xf8, 0x0f, 0x00};

//
// The CursorView contains many labels with different cursors.
//

class CursorView : public QWidget               // cursor view
{
public:
    CursorView();
};

//
// Constructs a cursor view.
//

CursorView::CursorView()                        // construct view
{
    struct List {
        CursorShape     shape;
        const char*     name;                   // cursor name
    };
    static List list[] = {
        { ArrowCursor,          "arrowCursor" },
        { UpArrowCursor,        "upArrowCursor" },
        { CrossCursor,          "crossCursor" },
        { WaitCursor,           "waitCursor" },
        { IbeamCursor,          "ibeamCursor" },
        { SizeVerCursor,        "sizeVerCursor" },
        { SizeHorCursor,        "sizeHorCursor" },
        { SizeBDiagCursor,      "sizeBDiagCursor" },
        { SizeFDiagCursor,      "sizeFDiagCursor" },
        { SizeAllCursor,        "sizeAllCursor" },
        { BlankCursor,          "blankCursor" },
        { SplitVCursor,         "splitVCursor" },
        { SplitHCursor,         "splitHCursor" },
        { PointingHandCursor,   "pointingHandCursor" },
        { ForbiddenCursor,      "forbiddenCursor" },
        { WhatsThisCursor,      "whatsThisCursor" }
    };

    setCaption( "CursorView" );                 // set window caption

    QGridLayout* grid = new QGridLayout( this, 5, 4, 20 );
    QLabel *label;

    int i=0;
    for ( int y=0; y<4; y++ ) {                 // create the small labels
        for ( int x=0; x<4; x++ ) {
            label = new QLabel( this );
            label->setCursor( QCursor( list[i].shape ) );
            label->setText( list[i].name );
            label->setAlignment( AlignCenter );
            label->setFrameStyle( QFrame::Box | QFrame::Raised );
            grid->addWidget( label, x, y );
            i++;
        }
    }

    QBitmap cb( cb_width, cb_height, cb_bits, TRUE );
    QBitmap cm( cm_width, cm_height, cm_bits, TRUE );
    QCursor custom( cb, cm );                   // create bitmap cursor

    label = new QLabel( this );                 // create the big label
    label->setCursor( custom );
    label->setText( "Custom bitmap cursor" );
    label->setAlignment( AlignCenter );
    label->setFrameStyle( QFrame::Box | QFrame::Sunken );
    grid->addMultiCellWidget( label, 4, 4, 0, 3 );

}

//
// Create and display a CursorView.
//

int main( int argc, char **argv )
{
    QApplication a( argc, argv );               // application object
    CursorView   v;                             // cursor view
    a.setMainWidget( &v );
    v.setCaption("Qt Example - Cursors");
    v.show();
    return a.exec();
}

See also Examples.


写你自己的布局管理器

这里我们提供了一个详细的例子。CardLayout类是从同名的Java布局管理器得到的灵感。它把项目（窗口部件或者嵌套的布局）布置到彼此的顶端，每个项目通过QLayout::spacing()偏移的。

要写自己的布局类，你必须像下面这样定义：

  • 一个用来存放被布局处理的项目的数据结构。每一个项目就是一个QLayoutItem。我们将在例子中使用一个QPtrList。
  • addItem()，如何向布局中添加一个项目。
  • setGeometry()，如何构成一个布局。
  • sizeHint()，布局优先选用的大小。
  • iterator()，如何迭代布局。

在绝大多数情况下，你也需要实现minimumSize()。

card.h

#ifndef CARD_H
#define CARD_H

#include <qlayout.h>
#include <qptrlist.h>

class CardLayout : public QLayout
{
public:
    CardLayout( QWidget *parent, int dist )
        : QLayout( parent, 0, dist ) { }
    CardLayout( QLayout* parent, int dist)
        : QLayout( parent, dist ) { }
    CardLayout( int dist )
        : QLayout( dist ) { }
    ~CardLayout();

    void addItem(QLayoutItem *item);
    QSize sizeHint() const;
    QSize minimumSize() const;
    QLayoutIterator iterator();
    void setGeometry(const QRect &rect);

private:
    QPtrList<QLayoutItem> list;
};

#endif

card.cpp

#include "card.h"

首先我们为布局定义一个迭代。布局迭代被布局系统用作内部处理图形窗口部件删除操作的。它们也可以被提供给应用程序员。

这里有两个两个不同的相关类：QLayoutIterator是一个可以提供给应用程序员可见的类，它是明确地被共享。QLayoutIterator包括一个可以做任何事情地QGLayoutIterator。我们必须生成一个知道如何迭代我们地布局类的QGLayoutIterator的子类。

在这种情况下，我们选择一个简单的实现：我们把一个整数索引和指针存储到一个列表中。每一个QGLayoutIterator的子类都必须实现current()、next()和takeCurrent()，还有一个构造函数。在我们的例子中我们不需要析构函数。

class CardLayoutIterator : public QGLayoutIterator
{
public:
    CardLayoutIterator( QPtrList<QLayoutItem> *l )
        : idx( 0 ), list( l ) { }

    QLayoutItem *current()
    { return idx < int(list->count()) ? list->at(idx) : 0;  }

    QLayoutItem *next()
    { idx++; return current(); }

    QLayoutItem *takeCurrent()
    { return list->take( idx ); }

private:
    int idx;
    QPtrList<QLayoutItem> *list;
};

我们必须实现QLayout:iterator()返回一个这个布局的QLayoutIterator。

QLayoutIterator CardLayout::iterator()
{
    return QLayoutIterator( new CardLayoutIterator(&list) );
}

addItem()实现了布局项目的默认布置策略。它必须被实现。它被QLayout::add()使用，被把一个布局作为父布局的QLayout的构造函数使用，并且它被用来实现自动添加这一特性。如果你的布局有需要参数的高级布置选项，你将必须提供像QGridLayout::addMultiCell()一样的额外的访问函数。

void CardLayout::addItem( QLayoutItem *item )
{
    list.append( item );
}

布局对项目的增加负有责任。因为QLayoutItem不继承QObject，我们必须人工地删除这些项目。QLayout::deleteAllItems()函数使用我们前面定义的迭代来删除布局中的所有项目。

CardLayout::~CardLayout()
{
    deleteAllItems();
}

setGeometry()函数实际上执行了这个布局。作为参数提供的矩形不包括margin()。如果相关的话，项目之间的距离请使用spacing()。

void CardLayout::setGeometry( const QRect &rect )
{
    QLayout::setGeometry( rect );

    QPtrListIterator<QLayoutItem> it( list );
    if (it.count() == 0)
        return;

    QLayoutItem *o;

    int i = 0;

    int w = rect.width() - ( list.count() - 1 ) * spacing();
    int h = rect.height() - ( list.count() - 1 ) * spacing();

    while ( (o = it.current()) != 0 ) {
        ++it;
        QRect geom( rect.x() + i * spacing(), rect.y() + i * spacing(),
                    w, h );
        o->setGeometry( geom );
        ++i;
    }
}

sizeHint()和minimumSize()通常情况下在实现中非常相似。这两个函数返回的大小应该包括spacing()，但不包括margin()。

QSize CardLayout::sizeHint() const
{
    QSize s( 0, 0 );
    int n = list.count();
    if ( n > 0 )
        s = QSize( 100, 70 ); // start with a nice default size
    QPtrListIterator<QLayoutItem> it( list );
    QLayoutItem *o;
    while ( (o = it.current()) != 0 ) {
        ++it;
        s = s.expandedTo( o->minimumSize() );
    }
    return s + n * QSize( spacing(), spacing() );
}

QSize CardLayout::minimumSize() const
{
    QSize s( 0, 0 );
    int n = list.count();
    QPtrListIterator<QLayoutItem> it( list );
    QLayoutItem *o;
    while ( (o = it.current()) != 0 ) {
        ++it;
        s = s.expandedTo( o->minimumSize() );
    }
    return s + n * QSize( spacing(), spacing() );
}

更多的注释

这个布局没有实现heightForWidth()。

我们忽略了QLayoutItem::isEmpty()，这也就是说这个布局将会把隐藏的窗口部件显示出来。

对于复杂的布局，通过存储计算结果可以使速度得到很大的提高。在这种情况下，实现QLayoutItem::invalidate()来把被存储的数据弄脏。

调用QLayoutItem::sizeHint()，其它的也许更浪费时间，如果你在同一个函数中再一次稍晚的情况下需要这个值，你应该把它存储成局部变量。

你不应该在同一个函数中对同一项目调用QLayoutItem::setGeometry()两次。如果这个项目有几个子窗口部件的话，它会很浪费时间，因为它将不得不每次都执行一个完整的布局。相反，计算几何位置并且设置它。（这不仅仅是应用于布局，如果你实现了你自己的resizeEvent()你应该做同样的事情。）

Copyright © 2002 Trolltech Trademarks 译者:Cavendish
Qt 3.0.5版


Customized Layoutmanager

This examples demonstrates how to write customized layout (geometry) managers like card layouts, border layout and flow layouts.

See also: Documentation of Geometry Management.

Header file of the flow layout:

/****************************************************************************
** $Id:  qt/flow.h   3.0.5   edited Oct 12 2001 $
**
** Definition of simple flow layout for custom layout example
**
** Created : 979899
**
** Copyright (C) 1997 by Trolltech AS.  All rights reserved.
**
** This file is part of an example program for Qt.  This example
** program may be used, distributed and modified without limitation.
**
*****************************************************************************/

#ifndef FLOW_H
#define FLOW_H

#include <qlayout.h>
#include <qptrlist.h>

class SimpleFlow : public QLayout
{
public:
    SimpleFlow( QWidget *parent, int border=0, int space=-1,
                const char *name=0 )
        : QLayout( parent, border, space, name ),
        cached_width(0) {}
    SimpleFlow( QLayout* parent, int space=-1, const char *name=0 )
        : QLayout( parent, space, name ),
        cached_width(0) {}
    SimpleFlow( int space=-1, const char *name=0 )
        : QLayout( space, name ),
        cached_width(0) {}

    ~SimpleFlow();

    void addItem( QLayoutItem *item);
    bool hasHeightForWidth() const;
    int heightForWidth( int ) const;
    QSize sizeHint() const;
    QSize minimumSize() const;
    QLayoutIterator iterator();
    QSizePolicy::ExpandData expanding() const;

protected:
    void setGeometry( const QRect& );

private:
    int doLayout( const QRect&, bool testonly = FALSE );
    QPtrList<QLayoutItem> list;
    int cached_width;
    int cached_hfw;

};

#endif

Implementation of the flow layout:

/****************************************************************************
** $Id:  qt/flow.cpp   3.0.5   edited Oct 12 2001 $
**
** Implementing your own layout: flow example
**
** Copyright (C) 1996 by Trolltech AS.  All rights reserved.
**
** This file is part of an example program for Qt.  This example
** program may be used, distributed and modified without limitation.
**
*****************************************************************************/

#include "flow.h"

class SimpleFlowIterator :public QGLayoutIterator
{
public:
    SimpleFlowIterator( QPtrList<QLayoutItem> *l ) :idx(0), list(l)  {}
    uint count() const;
    QLayoutItem *current();
    QLayoutItem *next();
    QLayoutItem *takeCurrent();

private:
    int idx;
    QPtrList<QLayoutItem> *list;

};

uint SimpleFlowIterator::count() const
{
    return list->count();
}

QLayoutItem *SimpleFlowIterator::current()
{
    return idx < int(count()) ? list->at(idx) : 0;
}

QLayoutItem *SimpleFlowIterator::next()
{
    idx++; return current();
}

QLayoutItem *SimpleFlowIterator::takeCurrent()
{
    return idx < int(count()) ? list->take( idx ) : 0;
}

SimpleFlow::~SimpleFlow()
{
    deleteAllItems();
}

int SimpleFlow::heightForWidth( int w ) const
{
    if ( cached_width != w ) {
        //Not all C++ compilers support "mutable" yet:
        SimpleFlow * mthis = (SimpleFlow*)this;
        int h = mthis->doLayout( QRect(0,0,w,0), TRUE );
        mthis->cached_hfw = h;
        return h;
    }
    return cached_hfw;
}

void SimpleFlow::addItem( QLayoutItem *item)
{
    list.append( item );
}

bool SimpleFlow::hasHeightForWidth() const
{
    return TRUE;
}

QSize SimpleFlow::sizeHint() const
{
    return minimumSize();
}

QSizePolicy::ExpandData SimpleFlow::expanding() const
{
    return QSizePolicy::NoDirection;
}

QLayoutIterator SimpleFlow::iterator()
{
    return QLayoutIterator( new SimpleFlowIterator( &list ) );
}

void SimpleFlow::setGeometry( const QRect &r )
{
    QLayout::setGeometry( r );
    doLayout( r );
}

int SimpleFlow::doLayout( const QRect &r, bool testonly )
{
    int x = r.x();
    int y = r.y();
    int h = 0;          //height of this line so far.
    QPtrListIterator<QLayoutItem> it(list);
    QLayoutItem *o;
    while ( (o=it.current()) != 0 ) {
        ++it;
        int nextX = x + o->sizeHint().width() + spacing();
        if ( nextX - spacing() > r.right() && h > 0 ) {
            x = r.x();
            y = y + h + spacing();
            nextX = x + o->sizeHint().width() + spacing();
            h = 0;
        }
        if ( !testonly )
            o->setGeometry( QRect( QPoint( x, y ), o->sizeHint() ) );
        x = nextX;
        h = QMAX( h,  o->sizeHint().height() );
    }
    return y + h - r.y();
}

QSize SimpleFlow::minimumSize() const
{
    QSize s(0,0);
    QPtrListIterator<QLayoutItem> it(list);
    QLayoutItem *o;
    while ( (o=it.current()) != 0 ) {
        ++it;
        s = s.expandedTo( o->minimumSize() );
    }
    return s;
}

Header file of the border layout:

/****************************************************************************
** $Id:  qt/border.h   3.0.5   edited Oct 12 2001 $
**
** Definition of simple flow layout for custom layout example
**
** Created : 979899
**
** Copyright (C) 1997 by Trolltech AS.  All rights reserved.
**
** This file is part of an example program for Qt.  This example
** program may be used, distributed and modified without limitation.
**
*****************************************************************************/

#ifndef BORDER_H
#define BORDER_H

#include <qlayout.h>
#include <qptrlist.h>

class BorderWidgetItem : public QWidgetItem
{
public:
    BorderWidgetItem( QWidget *w )
        : QWidgetItem( w )
    {}

    void setGeometry( const QRect &r )
    { widget()->setGeometry( r ); }

};

class BorderLayout : public QLayout
{
public:
    enum Position {
        West = 0,
        North,
        South,
        East,
        Center
    };

    struct BorderLayoutStruct
    {
        BorderLayoutStruct( QLayoutItem *i, Position p ) {
            item = i;
            pos = p;
        }

        QLayoutItem *item;
        Position pos;
    };

    enum SizeType {
        Minimum = 0,
        SizeHint
    };

    BorderLayout( QWidget *parent, int border = 0, int autoBorder = -1,
                  const char *name = 0 )
        : QLayout( parent, border, autoBorder, name ), cached( 0, 0 ), mcached( 0, 0 ),
          sizeDirty( TRUE ), msizeDirty( TRUE )
    {}

    BorderLayout( QLayout* parent, int autoBorder = -1, const char *name = 0 )
        : QLayout( parent, autoBorder, name  ), cached( 0, 0 ), mcached( 0, 0 ),
          sizeDirty( TRUE ), msizeDirty( TRUE )
    {}

    BorderLayout( int autoBorder = -1, const char *name = 0 )
        : QLayout( autoBorder, name ), cached( 0, 0 ), mcached( 0, 0 ),
          sizeDirty( TRUE ), msizeDirty( TRUE )
    {}

    ~BorderLayout();

    void addItem( QLayoutItem *item );

    void addWidget( QWidget *widget, Position pos );
    void add( QLayoutItem *item, Position pos );

    bool hasHeightForWidth() const;

    QSize sizeHint() const;
    QSize minimumSize() const;

    QLayoutIterator iterator();

    QSizePolicy::ExpandData expanding() const;

protected:
    void setGeometry( const QRect &rect );

private:
    void doLayout( const QRect &rect, bool testonly = FALSE );
    void calcSize( SizeType st );

    QPtrList<BorderLayoutStruct> list;
    QSize cached, mcached;
    bool sizeDirty, msizeDirty;

};

#endif

Implementation of the border layout:

/****************************************************************************
** $Id:  qt/border.cpp   3.0.5   edited Oct 12 2001 $
**
** Implementing your own layout: flow example
**
** Copyright (C) 1996 by Trolltech AS.  All rights reserved.
**
** This file is part of an example program for Qt.  This example
** program may be used, distributed and modified without limitation.
**
*****************************************************************************/

#include "border.h"

class BorderLayoutIterator : public QGLayoutIterator
{
public:
    BorderLayoutIterator( const QPtrList<BorderLayout::BorderLayoutStruct> *l )
        : idx( 0 ) , list( (QPtrList<BorderLayout::BorderLayoutStruct>*)l )
    {}

    uint count() const;
    QLayoutItem *current();
    BorderLayout::BorderLayoutStruct *currentStruct();
    void toFirst();
    QLayoutItem *next();
    QLayoutItem *takeCurrent();
    BorderLayoutIterator &operator++();

private:
    int idx;
    QPtrList<BorderLayout::BorderLayoutStruct> *list;

};

uint BorderLayoutIterator::count() const
{
    return list->count();
}

QLayoutItem *BorderLayoutIterator::current()
{
    return idx < (int)count() ? list->at( idx )->item : 0;
}

BorderLayout::BorderLayoutStruct *BorderLayoutIterator::currentStruct()
{
    return idx < (int)count() ? list->at( idx ) : 0;
}

void BorderLayoutIterator::toFirst()
{
    idx = 0;
}

QLayoutItem *BorderLayoutIterator::next()
{
    idx++;
    return current();
}

QLayoutItem *BorderLayoutIterator::takeCurrent()
{
    BorderLayout::BorderLayoutStruct *b
        = idx < int( list->count() ) ? list->take(  idx  ) : 0;
    QLayoutItem *item =  b ? b->item : 0;
    delete b;
    return item;
}

BorderLayoutIterator &BorderLayoutIterator::operator++()
{
    next();
    return *this;
}

BorderLayout::~BorderLayout()
{
    deleteAllItems();
}

void BorderLayout::addItem( QLayoutItem *item )
{
    add( item, West );
}

void BorderLayout::addWidget( QWidget *widget, Position pos )
{
    add( new BorderWidgetItem( widget ), pos );
}

void BorderLayout::add( QLayoutItem *item, Position pos )
{
    list.append( new BorderLayoutStruct( item, pos ) );
    sizeDirty = TRUE; msizeDirty = TRUE;
    calcSize( SizeHint ); calcSize( Minimum );
}

bool BorderLayout::hasHeightForWidth() const
{
    return FALSE;
}

QSize BorderLayout::sizeHint() const
{
    return cached;
}

QSize BorderLayout::minimumSize() const
{
    return cached;
}

QSizePolicy::ExpandData BorderLayout::expanding() const

{
    return QSizePolicy::BothDirections;
}

QLayoutIterator BorderLayout::iterator()
{
    return QLayoutIterator( new BorderLayoutIterator( &list ) );
}

void BorderLayout::setGeometry( const QRect &rct )
{
    QLayout::setGeometry( rct );
    doLayout( rct );
}

void BorderLayout::doLayout( const QRect &rct, bool /*testonly*/ )
{
    int ew = 0, ww = 0, nh = 0, sh = 0;
    int h = 0;

    BorderLayoutIterator it( &list );
    BorderLayoutStruct *o;
    BorderLayoutStruct *center = 0;
    while ( ( o = it.currentStruct() ) != 0 ) {
        ++it;

        if ( o->pos == North ) {
            o->item->setGeometry( QRect( rct.x(), nh, rct.width(), o->item->sizeHint().height() ) );
            nh += o->item->geometry().height() + spacing();
        }
        if ( o->pos == South ) {
            o->item->setGeometry( QRect( o->item->geometry().x(), o->item->geometry().y(),
                                         rct.width(), o->item->sizeHint().height() ) );
            sh += o->item->geometry().height() + spacing();
            o->item->setGeometry( QRect( rct.x(), rct.y() + rct.height() - sh + spacing(),
                                         o->item->geometry().width(), o->item->geometry().height() ) );
        }
        if ( o->pos == Center )
            center = o;
    }

    h = rct.height() - nh - sh;

    it.toFirst();
    while ( ( o = it.currentStruct() ) != 0 ) {
        ++it;

        if ( o->pos == West ) {
            o->item->setGeometry( QRect( rct.x() + ww, nh, o->item->sizeHint().width(), h ) );
            ww += o->item->geometry().width() + spacing();
        }
        if ( o->pos == East ) {
            o->item->setGeometry( QRect( o->item->geometry().x(), o->item->geometry().y(),
                                         o->item->sizeHint().width(), h ) );
            ew += o->item->geometry().width() + spacing();
            o->item->setGeometry( QRect( rct.x() + rct.width() - ew + spacing(), nh,
                                         o->item->geometry().width(), o->item->geometry().height() ) );
        }
    }

    if ( center )
        center->item->setGeometry( QRect( ww, nh, rct.width() - ew - ww, h ) );
}

void BorderLayout::calcSize( SizeType st )
{
    if ( ( st == Minimum && !msizeDirty ) ||
         ( st == SizeHint && !sizeDirty ) )
        return;

    int w = 0, h = 0;

    BorderLayoutIterator it( &list );
    BorderLayoutStruct *o;
    while ( ( o = it.currentStruct() ) != 0 ) {
        ++it;
        if ( o->pos == North ||
             o->pos == South ) {
            if ( st == Minimum )
                h += o->item->minimumSize().height();
            else
                h += o->item->sizeHint().height();
        }
        else if ( o->pos == West ||
                  o->pos == East ) {
            if ( st == Minimum )
                w += o->item->minimumSize().width();
            else
                w += o->item->sizeHint().width();
        } else {
            if ( st == Minimum ) {
                h += o->item->minimumSize().height();
                w += o->item->minimumSize().width();
            }
            else {
                h += o->item->sizeHint().height();
                w += o->item->sizeHint().width();
            }
        }
    }

    if ( st == Minimum ) {
        msizeDirty = FALSE;
        mcached = QSize( w, h );
    } else {
        sizeDirty = FALSE;
        cached = QSize( w, h );
    }

    return;
}

Header file of the card layout:

/****************************************************************************
** $Id:  qt/card.h   3.0.5   edited Oct 12 2001 $
**
** Definition of simple flow layout for custom layout example
**
** Created : 979899
**
** Copyright (C) 1997 by Trolltech AS.  All rights reserved.
**
** This file is part of an example program for Qt.  This example
** program may be used, distributed and modified without limitation.
**
*****************************************************************************/

#ifndef CARD_H
#define CARD_H

#include <qlayout.h>
#include <qptrlist.h>

class CardLayout : public QLayout
{
public:
    CardLayout( QWidget *parent, int dist )
        : QLayout( parent, 0, dist ) {}
    CardLayout( QLayout* parent, int dist)
        : QLayout( parent, dist ) {}
    CardLayout( int dist )
        : QLayout( dist ) {}
    ~CardLayout();

    void addItem( QLayoutItem *item );
    QSize sizeHint() const;
    QSize minimumSize() const;
    QLayoutIterator iterator();
    void setGeometry( const QRect &rect );

private:
    QPtrList<QLayoutItem> list;

};

#endif

Implementation of the card layout:

/****************************************************************************
** $Id:  qt/card.cpp   3.0.5   edited Oct 12 2001 $
**
** Implementing your own layout: flow example
**
** Copyright (C) 1996 by Trolltech AS.  All rights reserved.
**
** This file is part of an example program for Qt.  This example
** program may be used, distributed and modified without limitation.
**
*****************************************************************************/

#include "card.h"

class CardLayoutIterator :public QGLayoutIterator
{
public:
    CardLayoutIterator( QPtrList<QLayoutItem> *l )
        : idx( 0 ), list( l )  {}

    QLayoutItem *current();
    QLayoutItem *next();
    QLayoutItem *takeCurrent();

private:
    int idx;
    QPtrList<QLayoutItem> *list;
};

QLayoutItem *CardLayoutIterator::current()
{
    return idx < int( list->count() ) ? list->at( idx ) : 0;
}

QLayoutItem *CardLayoutIterator::next()
{
    idx++; return current();
}

QLayoutItem *CardLayoutIterator::takeCurrent()
{
    return idx < int( list->count() ) ?list->take( idx ) : 0;
}

QLayoutIterator CardLayout::iterator()
{
    return QLayoutIterator(  new CardLayoutIterator( &list )  );
}

CardLayout::~CardLayout()
{
    deleteAllItems();
}

void CardLayout::addItem(  QLayoutItem *item  )
{
    list.append( item );
}

void CardLayout::setGeometry( const QRect &rct )
{
    QLayout::setGeometry( rct );

    QPtrListIterator<QLayoutItem> it( list );
    if ( it.count() == 0 )
        return;

    QLayoutItem *o;

    int i = 0;

    int w = rct.width() - ( list.count() - 1 ) * spacing();
    int h = rct.height() - ( list.count() - 1 ) * spacing();

    while ( ( o=it.current() ) != 0 ) {
        ++it;
        QRect geom( rct.x() + i * spacing(), rct.y() + i * spacing(),
                    w, h  );
        o->setGeometry(  geom  );
        ++i;
    }
}

QSize CardLayout::sizeHint() const
{
    QSize s(0,0);
    int n = list.count();
    if ( n > 0 )
        s = QSize(100,70); //start with a nice default size
    QPtrListIterator<QLayoutItem> it(list);
    QLayoutItem *o;
    while ( (o=it.current()) != 0 ) {
        ++it;
        s = s.expandedTo( o->minimumSize() );
    }
    return s + n*QSize(spacing(),spacing());
}

QSize CardLayout::minimumSize() const
{
    QSize s(0,0);
    int n = list.count();
    QPtrListIterator<QLayoutItem> it(list);
    QLayoutItem *o;
    while ( (o=it.current()) != 0 ) {
        ++it;
        s = s.expandedTo( o->minimumSize() );
    }
    return s + n*QSize(spacing(),spacing());
}

Main:

/****************************************************************************
** $Id:  qt/main.cpp   3.0.5   edited Oct 12 2001 $
**
** Main for custom layout example
**
** Copyright (C) 1996 by Trolltech AS.  All rights reserved.
**
** This file is part of an example program for Qt.  This example
** program may be used, distributed and modified without limitation.
**
*****************************************************************************/

#include "flow.h"
#include "border.h"
#include "card.h"

#include <qapplication.h>
#include <qlabel.h>
#include <qcolor.h>
#include <qgroupbox.h>
#include <qpushbutton.h>
#include <qmultilineedit.h>
#include <qcolor.h>

int main( int argc, char **argv )
{
    QApplication a( argc, argv );

    QWidget *f = new QWidget;
    QBoxLayout *gm = new QVBoxLayout( f, 5 );

    SimpleFlow *b1 = new SimpleFlow( gm );

    b1->add( new QPushButton( "Short", f ) );
    b1->add( new QPushButton( "Longer", f ) );
    b1->add( new QPushButton( "Different text", f ) );
    b1->add( new QPushButton( "More text", f ) );
    b1->add( new QPushButton( "Even longer button text", f ) );
    QPushButton* qb = new QPushButton( "Quit", f );
    a.connect( qb, SIGNAL( clicked() ), SLOT( quit() ) );
    b1->add( qb );

    QWidget *wid = new QWidget( f );

    BorderLayout *large = new BorderLayout( wid );
    large->setSpacing( 5 );
    large->addWidget( new QPushButton( "North", wid ), BorderLayout::North );
    large->addWidget( new QPushButton( "West", wid ), BorderLayout::West );
    QMultiLineEdit* m = new QMultiLineEdit( wid );
    m->setText( "Central\nWidget" );
    large->addWidget( m, BorderLayout::Center );
    QWidget *east1 = new QPushButton( "East", wid );
    large->addWidget( east1, BorderLayout::East );
    QWidget *east2 = new QPushButton( "East 2", wid );
    large->addWidget( east2 , BorderLayout::East );
    large->addWidget( new QPushButton( "South", wid ), BorderLayout::South );
    //Left-to-right tab order looks better:
    QWidget::setTabOrder( east2, east1 );
    gm->addWidget( wid );

    wid = new QWidget( f );
    CardLayout *card = new CardLayout( wid, 10 );

    QWidget *crd = new QWidget( wid );
    crd->setBackgroundColor( Qt::red );
    card->add( crd );
    crd = new QWidget( wid );
    crd->setBackgroundColor( Qt::green );
    card->add( crd );
    crd = new QWidget( wid );
    crd->setBackgroundColor( Qt::blue );
    card->add( crd );
    crd = new QWidget( wid );
    crd->setBackgroundColor( Qt::white );
    card->add( crd );
    crd = new QWidget( wid );
    crd->setBackgroundColor( Qt::black );
    card->add( crd );
    crd = new QWidget( wid );
    crd->setBackgroundColor( Qt::yellow );
    card->add( crd );

    gm->addWidget( wid );

    QLabel* s = new QLabel( f );
    s->setText( "outermost box" );
    s->setFrameStyle( QFrame::Panel | QFrame::Sunken );
    s->setAlignment( Qt::AlignVCenter | Qt::AlignHCenter );
    gm->addWidget( s );
    a.setMainWidget( f );
    f->setCaption("Qt Example - Custom Layout");
    f->show();

    int result = a.exec();
    delete f;
    return result;
}

See also Examples.


Style overview

A style in Qt implements the look and feel found in GUIs on different platforms. For instance the Windows style used in Windows and the Motif style that are common on many Unix platforms.

This is a short guide that describes the steps that are necessary to get started creating and using custom styles with the style API in Qt 3.x. First, we go through the steps necessary to create a style: 1) picking a base style to inherit from and 2) re-implementing the necessary functions in the derived class. Then we show how to use the new style from within your own applications, or as a plugin together with existing Qt applications.

Creating a custom style

1. Pick a base style to inherit from.

The first step is to pick one of the base styles provided with Qt to build your custom style on. Which of the available styles to start from does of course depend on what look & feel you want. Basically you should choose from the QWindowsStyle derived classes or the QMotifStyle derived classes. These are the two base look & feel classes in the Qt style engine. Inheriting directly from QCommonStyle is also an option if you want to start almost from scratch when implementing your style. In this simple example we will inherit from QWindowsStyle.

2. Re-implement the necessary functions in your derived class.

Depending on which parts of the base style you want to change, you have to re-implement the functions that are used to draw those parts of the interface. If you take a look at the QStyle documentation, you will find a list of the different primitives, controls and complex controls. You will also find an illustration that shows where the different primitives, controls and complex controls are used. In this example we will first change the look of the standard arrows that are used in the QWindowsStyle. The arrows are PrimitiveElements that are drawn in the drawPrimitive() function, therefore we need to re-implement that function. We get the following class declaration:

#include <qwindowsstyle.h>

class CustomStyle : public QWindowsStyle {
    Q_OBJECT
public:
    CustomStyle();
    ~CustomStyle();

    void drawPrimitive( PrimitiveElement pe,
                        QPainter *p,
                        const QRect & r,
                        const QColorGroup & cg,
                        SFlags flags = Style_Default,
                        const QStyleOption & = QStyleOption::Default ) const;

private:
    // Disabled copy constructor and operator=
    CustomStyle( const CustomStyle & );
    CustomStyle& operator=( const CustomStyle & );
};

Note that we disable the copy constructor and the '=' operator for our style. QObject is the base class for all style classes in Qt, and a QObject inherently cannot be copied; there are some aspects of it that are not copyable.

From the QStyle docs we see that PE_ArrowUp, PE_ArrowDown, PE_ArrowLeft and PE_ArrowRight are the primitives we need to do something with. We get the following in our drawPrimitive() function:

CustomStyle::CustomStyle()
{
}

CustomStyle::~CustomStyle()
{
}

void CustomStyle::drawPrimitive( PrimitiveElement pe,
                                 QPainter * p,
                                 const QRect & r,
                                 const QColorGroup & cg,
                                 SFlags flags,
                                 const QStyleOption & opt ) const
{
    // we are only interested in the arrows
    if (pe >= PE_ArrowUp && pe <= PE_ArrowLeft) {
        QPointArray pa( 3 );
        // make the arrow cover half the area it is supposed to be
        // painted on
        int x = r.x();
        int y = r.y();
        int w = r.width() / 2;
        int h = r.height() / 2;
        x += (r.width() - w) / 2;
        y += (r.height() - h) /2;

        switch( pe ) {
        case PE_ArrowDown:
            pa.setPoint( 0, x, y );
            pa.setPoint( 1, x + w, y );
            pa.setPoint( 2, x + w / 2, y + h );
            break;
        case PE_ArrowUp:
            pa.setPoint( 0, x, y + h );
            pa.setPoint( 1, x + w, y + h );
            pa.setPoint( 2, x + w / 2, y );
            break;
        case PE_ArrowLeft:
            pa.setPoint( 0, x + w, y );
            pa.setPoint( 1, x + w, y + h );
            pa.setPoint( 2, x, y + h / 2 );
            break;
        case PE_ArrowRight:
            pa.setPoint( 0, x, y );
            pa.setPoint( 1, x, y + h );
            pa.setPoint( 2, x + w, y + h / 2 );
            break;
        default: break;

        }

        // use different colors to indicate that the arrow is
        // enabled/disabled
        if ( flags & Style_Enabled ) {
            p->setPen( cg.mid() );
            p->setBrush( cg.brush( QColorGroup::ButtonText ) );
        } else {
            p->setPen( cg.buttonText() );
            p->setBrush( cg.brush( QColorGroup::Mid ) );
        }
        p->drawPolygon( pa );
    } else {
        // let the base style handle the other primitives
        QWindowsStyle::drawPrimitive( pe, p, r, cg, flags, data );
    }
}

Using a custom style

There are several ways of using a custom style in a Qt application. The easiest and most simple way is to include the following lines of code in the application's main() function:

#include "customstyle.h"

int main( int argc, char ** argv )
{
    QApplication::setStyle( new CustomStyle() );
    // do the usual routine on creating your QApplication object etc.
}

Note that you also have to include the customstyle.h and customstyle.cpp files in your project.

2. Creating and using a pluggable style

You may want to use your custom style in a Qt application that you don't want to, or have the opportunity to recompile. The Qt Plugin system makes it possible to create styles as plugins. Styles created as plugins are loaded as shared objects at runtime by Qt itself. Please refer to the Qt Plugin documentation for more information on how to go about creating a style plugin.

Compile your plugin and put it into $QTDIR/plugins/styles. We now have a pluggable style that Qt can load automatically. To use your new style with existing applications, simply start the application with the following argument:

./application -style custom

The application should appear with the look & feel from the custom style you implemented.


Database Classes

These classes provide access to SQL databases.

QDataBrowser | Data manipulation and navigation for data entry forms
QDataTable | Flexible SQL table widget that supports browsing and editing
QDataView | Read-only SQL forms
QSql | Namespace for Qt SQL identifiers that need to be global-like
QSqlCursor | Browsing and editing of SQL tables and views
QSqlDatabase | Used to create SQL database connections and provide transaction handling
QSqlDriver | Abstract base class for accessing SQL databases
QSqlEditorFactory | Used to create the editors used by QDataTable and QSqlForm
QSqlError | SQL database error information
QSqlField | Manipulates the fields in SQL database tables and views
QSqlFieldInfo | Stores meta data associated with a SQL field
QSqlForm | Creates and manages data entry forms tied to SQL databases
QSqlIndex | Functions to manipulate and describe QSqlCursor and QSqlDatabase indexes
QSqlPropertyMap | Used to map widgets to SQL fields
QSqlQuery | Means of executing and manipulating SQL statements
QSqlRecord | Encapsulates a database record, i.e. a set of database fields
QSqlRecordInfo | Encapsulates a set of database field meta data
QSqlResult | Abstract interface for accessing data from SQL databases


Format of the QDataStream Operators

The QDataStream allows you to serialize some of the Qt data types. The table below lists the data types that QDataStream can serialize and how they are represented.

  • Q_INT8
    • signed byte
  • Q_INT16
    • signed 16 bit integer
  • Q_INT32
    • signed 32 bit integer
  • Q_UINT8
    • unsigned byte
  • Q_UINT16
    • unsigned 16 bit integer
  • Q_UINT32
    • unsigned 32 bit integer
  • float
    • 32-bit floating point number using the standard IEEE-754 format
  • double
    • 64-bit floating point number using the standard IEEE-754 format
  • char *
    • The size of the string including the terminating 0 (Q_UINT32)
    • The string bytes including the terminating 0
    The null string is represented as (Q_UINT32) 0.
  • QBitArray
    • The array size (Q_UINT32)
    • The array bits, i.e. (size + 7)/8 bytes
  • QBrush
    • The brush style (Q_UINT8)
    • The brush color (QColor)
    • If style is CustomPattern, the brush pixmap (QPixmap)
  • QByteArray
    • The array size (Q_UINT32)
    • The array bytes, i.e. size bytes
  • QCString
    • The size of the string including the terminating 0 (Q_UINT32)
    • The string bytes including the terminating 0
    The null string is represented as (Q_UINT32) 0.
  • QColor
    • RGB value serialized as a Q_UINT32
  • QColorGroup
    • foreground (QBrush)
    • button (QBrush)
    • light (QBrush)
    • midLight (QBrush)
    • dark (QBrush)
    • mid (QBrush)
    • text (QBrush)
    • brightText (QBrush)
    • ButtonText (QBrush)
    • base (QBrush)
    • background (QBrush)
    • shadow (QBrush)
    • highlight (QBrush)
    • highlightedText (QBrush)
  • QCursor
    • Shape id (Q_INT16)
    • If shape is BitmapCursor: The bitmap (QPixmap), mask (QPixmap) and hot spot (QPoint)
  • QDate
    • Julian day (Q_UINT32)
  • QDateTime
    • Date (QDate)
    • Time (QTime)
  • QFont
    • The point size (Q_INT16)
    • The style hint (Q_UINT8)
    • The char set (Q_UINT8)
    • The weight (Q_UINT8)
    • The font bits (Q_UINT8)
  • QImage
    • Save it as a PNG image.
  • QMap
    • The number of items (Q_UINT32)
    • For all items, the key and value
  • QPalette
    • active (QColorGroup)
    • disabled (QColorGroup)
    • inactive (QColorGroup)
  • QPen
    • The pen styles (Q_UINT8)
    • The pen width (Q_UINT8)
    • The pen color (QColor)
  • QPicture
    • The size of the picture data (Q_UINT32)
    • The raw bytes of picture data (char)
  • QPixmap
    • Save it as a PNG image.
  • QPoint
    • The x coordinate (Q_INT32)
    • The y coordinate (Q_INT32)
  • QPointArray
    • The array size (Q_UINT32)
    • The array points (QPoint)
  • QRect
    • left (Q_INT32)
    • top (Q_INT32)
    • right (Q_INT32)
    • bottom (Q_INT32)
  • QRegion
    • The size of the data, i.e. 8 + 16 * (number of rectangles) (Q_UINT32)
    • QRGN_RECTS (Q_INT32)
    • The number of rectangles (Q_UINT32)
    • The rectangles in sequential order (QRect)
  • QSize
    • width (Q_INT32)
    • height (Q_INT32)
  • QString
    • If the string is null: 0xffffffff (Q_UINT32)
    • Otherwise: The string length (Q_UINT32) followed by the data in UTF-16
  • QTime
    • Milliseconds since midnight (Q_UINT32)
  • QValueList
    • The number of list elements (Q_UINT32)
    • All the elements in sequential order
  • QVariant
    • The type of the data (Q_UINT32)
    • The data of the specified type
  • QWMatrix
    • m11 (double)
    • m12 (double)
    • m21 (double)
    • m22 (double)
    • dx (double)
    • dy (double)


Digital Clock

This example displays a digital LCD clock that can switch between time and date.

Header file:

/****************************************************************************
** $Id:  qt/dclock.h   3.0.5   edited Oct 12 2001 $
**
** Copyright (C) 1992-2000 Trolltech AS.  All rights reserved.
**
** This file is part of an example program for Qt.  This example
** program may be used, distributed and modified without limitation.
**
*****************************************************************************/

#ifndef DCLOCK_H
#define DCLOCK_H

#include <qlcdnumber.h>

class DigitalClock : public QLCDNumber          // digital clock widget
{
    Q_OBJECT
public:
    DigitalClock( QWidget *parent=0, const char *name=0 );

protected:                                      // event handlers
    void        timerEvent( QTimerEvent * );
    void        mousePressEvent( QMouseEvent * );

private slots:                                  // internal slots
    void        stopDate();
    void        showTime();

private:                                        // internal data
    void        showDate();

    bool        showingColon;
    int         normalTimer;
    int         showDateTimer;
};

#endif // DCLOCK_H

Implementation:

/****************************************************************************
** $Id:  qt/dclock.cpp   3.0.5   edited Oct 12 2001 $
**
** Copyright (C) 1992-2000 Trolltech AS.  All rights reserved.
**
** This file is part of an example program for Qt.  This example
** program may be used, distributed and modified without limitation.
**
*****************************************************************************/

#include "dclock.h"
#include <qdatetime.h>

//
// Constructs a DigitalClock widget with a parent and a name.
//

DigitalClock::DigitalClock( QWidget *parent, const char *name )
    : QLCDNumber( parent, name )
{
    showingColon = FALSE;
    setFrameStyle( QFrame::Panel | QFrame::Raised );
    setLineWidth( 2 );                          // set frame line width
    showTime();                                 // display the current time
    normalTimer = startTimer( 500 );            // 1/2 second timer events
    showDateTimer = -1;                         // not showing date
}

//
// Handles timer events for the digital clock widget.
// There are two different timers; one timer for updating the clock
// and another one for switching back from date mode to time mode.
//

void DigitalClock::timerEvent( QTimerEvent *e )
{
    if ( e->timerId() == showDateTimer )        // stop showing date
        stopDate();
    else {                                      // normal timer
        if ( showDateTimer == -1 )              // not showing date
            showTime();
    }
}

//
// Enters date mode when the left mouse button is pressed.
//

void DigitalClock::mousePressEvent( QMouseEvent *e )
{
    if ( e->button() == QMouseEvent::LeftButton )               // left button pressed
        showDate();
}

//
// Shows the current date in the internal lcd widget.
// Fires a timer to stop showing the date.
//

void DigitalClock::showDate()
{
    if ( showDateTimer != -1 )                  // already showing date
        return;
    QDate date = QDate::currentDate();
    QString s;
    s.sprintf( "%2d %2d", date.month(), date.day() );
    display( s );                               // sets the LCD number/text
    showDateTimer = startTimer( 2000 );         // keep this state for 2 secs
}

//
// Stops showing the date.
//

void DigitalClock::stopDate()
{
    killTimer( showDateTimer );
    showDateTimer = -1;
    showTime();
}

//
// Shows the current time in the internal lcd widget.
//

void DigitalClock::showTime()
{
    showingColon = !showingColon;               // toggle/blink colon
    QString s = QTime::currentTime().toString().left(5);
    if ( !showingColon )
        s[2] = ' ';
    if ( s[0] == '0' )
        s[0] = ' ';
    display( s );                               // set LCD number/text
}

Main:

/****************************************************************************
** $Id:  qt/main.cpp   3.0.5   edited Oct 12 2001 $
**
** Copyright (C) 1992-2000 Trolltech AS.  All rights reserved.
**
** This file is part of an example program for Qt.  This example
** program may be used, distributed and modified without limitation.
**
*****************************************************************************/

#include "dclock.h"
#include <qapplication.h>

int main( int argc, char **argv )
{
    QApplication a( argc, argv );
    DigitalClock *clock = new DigitalClock;
    clock->resize( 170, 80 );
    a.setMainWidget( clock );
    clock->setCaption("Qt Example - Digital Clock");
    clock->show();
    return a.exec();
}

See also Examples.


Qt Demo

This program shows off some of Qt's widgets and functionality. It isn't intended as a code example, but rather as a single application that you can run to see many of Qt's features.

See $QTDIR/examples/demo for the source code.

See also Examples.