2017年12月13日 星期三

Qt--一个MDI图形应用框架

Qt:一个MDI图形应用框架

原创 2012年07月16日 09:55:46
(本文接上篇“概述")
(Qt Library目前的版本为4.8,以下本文的程序将以此版本为主。)
三、Gt的GUI
Qt的优势在于GUI(本人的理解,至少以前如此,现在则未必),所以了解Qt,也是从图形界面的UI开始。
Qt有几百个类,与图形有关的估计有一半以上。本文主要介绍基于window的图形编程接口,另外稍微介绍一下OpenGL,可以为程序添加三维显示。
1.QWidget
这个是所有window的基类,类似于MFC中的CWnd,提供了许多基类方法。在做GUI时,应仔细阅读其说明文档。
2.滚动条
Qt窗口的滚动条是两个"控件“,需要手工添加(当然,Qt中也有一些自带滚动条的窗体类),不如Windows窗口中,滚动条是窗口的一个属性,凭设置就可以添加滚动条,但Windows中的滚动条是”假“的,需要手工编程控制其移动,而Qt在这点上要简单得多。
3.父子窗口
Qt中一个独特的现象是创建一个Widget时,可以指定一个父Widget,当父Widget销毁时,父Widget会遍历其子Widget,自动销毁子Widget,这样我们就不需要delete子窗口了。这是Qt内存管理的一个方法,对窗口来讲是合适的,由于我们不知道窗口何时销毁,所以必须将非窗口的东西(与窗口的生命期不同)拿出来,放到诸如document中存储,我们手工管理其生存周期。
4. 四种图形界面绘制方式
在Qt窗体下,可以有四种方式构成我们的图形界面,两种是基于文本(块)的格式化布局方式:通常的Window控件;QML控件,两种基于图形的任意布局方式:一种是无对象的,自己绘制;另一种是继承于GraphicsItem类的,一个图形是一个对象。以下分别介绍一下。
基于window控件的格式化GUI:这是最通常的一种UI方式,目前我们大量的对话窗口和Web页就是基于这种方式,这种方式是一种文本方式显示和录入方式。在Qt下,也提供了若干显示控件,可以满足基本的用户文本交换功能,当然,与Windows下的大量丰富的控件相比,Qt的控件就太”寒酸“了。
基于QML控件的格式化GUI:Qt中有专门显示html控件的窗口,但不知道为什么自己提出了一个叫QML(Declarative markup language)的东西,该技术被称为Qt Quick。从字面来看,该技术是提供一种快速创建UI的方法,但既然html已经广为应用,为什么还另起炉灶?该技术基本上与flash、Silverlight等属于同类东西。QML中的可视化控件也并不特别丰富,现在,QML可能与Silverlight一样,受到来自HTML5的强大威胁。
自由绘制GUI:类似于Windows中的图形绘制,在窗口刷新时,需要自己重绘;作为图形GUI,这种方式是最原始的,当然也是最”轻量级“的。为了满足跨平台的要求,所有绘制的代码只能在窗口的paintEvent中完成(类似于windows窗口的onpaint),在其他方法中,设置需要重新绘制的窗口的位置、大小,则Qt会将若干重绘请求,合并执行,图形就更新了,这与Windows不同,在windows中,例如在onmousemove事件中绘制图形,依然有效,由此想到,是否Qt的绘制效率要低于Windows,因为每次刷新时,Qt实际上是要绘制整个画面的(在后台进行),裁剪出需要更新的部分,更新到前台(类似于双缓冲),而Windows的重绘命令可以由用户按需要发出(系统也可以发出,如其他窗口遮挡住本窗口再移开时)。当然,Qt的这种处理方式具有普遍性,以普遍性(跨平台)来牺牲效率,是值得的。
基于图形元素(继承于GraphicsItem)的GUI:与自由绘制相比,该方式是”重量级“的。该方式实际上是对点、线、圆等的封装,使其具有更强的操作性,例如,支持局部坐标及其变换、无需用户重绘、覆盖、碰撞检测、成组等许多图形操作实用的功能。如果我们的应用需要将图形当做元素来处理,而这些处理又是通常的操作,并不复杂,那么采用这种方式最好。其实,将图形元素化,并不困难,凡是具有计算机图形学背景的技术人员,都可以编写出来。
四、一个MDI框架
大多数的复杂应用,以MDI最为常见,本文就介绍一个基于MDI的图形应用框架。
由Wizard生成的程序框架包括如下文件:
main.cpp:程序的入口,这个基本不用修改。如果需要支持中文,可在此选择设置字符集。
mainwindow.cpp:MDI的主窗口,我们最顶层的设计(如菜单),和跨文档的操作,都需在这里完成。
mainwindow.ui:界面文件,这里我们需要加一个mdiarea,用来容纳各子文档窗口。其他诸如status bar,menu bar,tool bar等已经添加了。在界面设计时,可以添加Action,slot,signal,其实他们也可以手工在h,cpp文件中添加,这个依赖于个人的习惯。
对于Action,它的trigger方法没有参数,当菜单项较多时,需要为每个菜单项写一个slot函数,实在麻烦,这点上不如Windows的菜单,可以“映射”到一个处理函数,根据传入的参数判断哪个菜单项被按下。
我们建文件时,应为每种View建一个View文件,如果几个View有共同的数据,则这几个View可以共享一种Document。本文将建4种View,共享1种document。整个程序的大致类结构如下图所示。图中,有4个View(包含的View不算),它们都拥有一个CDoc和MainWindowBase的引用。当View中内容发生更新时,如需要,则通知CDoc和主框架窗口,随着View的变化做相应调整。如果MainWindow类与各View类处于不同的文件,采用双向关联时,会发生循环引用,所以在MainWindow上加一个基类来解决这个问题。
1. 自由绘制图形View
无疑,这个View的代码最多,因为需要自己创建诸如Line,Rectangle等图形元素,这些图形元素的显示变换也需要自己处理。CElementView继承于QWidget,为给它加上滚动条,这个类又包含在一个基类为QScrollArea的继承类中,由该类处理滚动条。本文设计中,这个View最复杂,它实际上包含了3个子View,如下图所示。
Qt中分割条也是一个窗体,比较复杂地分割窗体的的示例代码如下。(上图的效果)
  1. m_pvsplitter= new QSplitter(Qt::Vertical,this);  
  2.  m_pvsplitter->resize(400,400);  
  3.   
  4. m_phsplitter= new QSplitter(Qt::Horizontal,m_pvsplitter);  
  5.   
  6. m_ptreeview = new CTreeView(m_phsplitter,m_pMainWin, m_pdoc);  
  7. m_ptreeview->resize(100,300);  
  8. m_pelementview = new CElementView(0,m_pMainWin, m_pdoc);  
  9.   
  10. ScrollWindow *elementwin = new ScrollWindow(m_phsplitter,m_pelementview, 300,300);  
  11.   
  12.  m_phsplitter->addWidget(m_ptreeview);  
  13.  m_phsplitter->addWidget(elementwin);  
  14.  m_phsplitter->setStretchFactor(1,1);  
  15.  m_phsplitter->resize(400,300);  
  16.   
  17.  m_pinfoview = new CInfoView(m_pvsplitter,m_pMainWin, m_pdoc);  
  18.  m_pinfoview->resize(400,100);  
  19.   
  20. m_pvsplitter->addWidget(m_phsplitter);  
  21. m_pvsplitter->addWidget(m_pinfoview);  
  22. m_pvsplitter->setStretchFactor(0,1);  
关于图形元素的编写,难度倒不大,就是麻烦,这里不再讨论。
2. 图形元素View
与第一View相比,采用Qt内置的图形元素,代码量会少不少,图形库大部分现成,所有图形元素都继承于QGraphicsItem,目前支持的标准图形元素有(摘自Qt文档):
QGraphicsEllipseItem  provides an ellipse item 
QGraphicsLineItem       provides a line item 
QGraphicsPathItem       provides an arbitrary path item 
QGraphicsPixmapItem provides a pixmap item 
QGraphicsPolygonItem provides a polygon item 
QGraphicsRectItem       provides a rectangular item 
QGraphicsSimpleTextItem provides a simple text label item 
QGraphicsTextItem      provides an advanced text browser item 
可能用到的还有QGraphicsPixmapItem、QGraphicsPathItem、QGraphicsItemAnimation和QGraphicsItemGroup,提供图片、绘制路径、动画和成组功能。通常,Qt提供的方法足够了,但要实现“精确”控制,仍需要自己实现。例如,Qt中线的“拾取”比较费劲,因为它要求鼠标点必须严格在线上,而合理杂做法是鼠标点距离线的小于,例如2个像素即可,这时,需要覆盖QGraphicsLineItem的contains方法。代码如下。
  1. typedef struct {float x,y; } f2Point;  
  2. typedef struct { float A,B,C; } fEqLine;   //Ax+By+C=0  
  3.     
  4. bool MatchSegment(const f2Point &mp,const f2Point &one, const f2Point &two)       //匹配线段  
  5. {  
  6.   fEqLine temp;  
  7.   double dd;  
  8.   
  9.   temp.A=one.y-two.y;  
  10.   temp.B=two.x-one.x;  
  11.   temp.C=-(one.x*lin.A+one.y*lin.B);  
  12.   
  13.   dd=fabs(temp.A*mp.x+temp.B*mp.y+(double)temp.C)/sqrt((double)temp.A*temp.A+temp.B*temp.B);  
  14.   if(dd<MatchDiff_Win)  
  15.   {  
  16.      if((mp.x-one.x)*(mp.x-two.x)+(mp.y-one.y)*(mp.y-two.y)<0) return true;  
  17.   }  
  18.   return false;  
  19. }  
  20.   
  21.   
  22. bool  contains ( const QPointF & point ) const  
  23. {  
  24.   //  if(this->group()) return false;           //这一行可作为加入组时使用  
  25.   
  26.     f2Point mp = {point.x(), point.y()};  
  27.     f2Point one ={this->line().x1(),this->line().y1()};  
  28.     f2Point two ={this->line().x2(),this->line().y2()};  
  29.   
  30.    return MatchSegment(mp,one, two);  
  31. }  
另一个需要改变的是当图形元素成组时,鼠标的选取与我们通常的模式不同,因此有了上面contains方法中的第一行。
在GraphicsScene模式下,各种鼠标事件、图形变换等都单独成为一个类,不知何故?这样会使类个数急剧上升。
3. OpenGL View
Qt可以显示SVG图形,也支持OpenGL,也显示出Qt想图形显示”通吃“的理想。增加对OpenGL的支持,也就意味着我们可以使图形更炫:显示三维图形。本文不涉及如何构建三维图形,如果已经写好OpenGL代码,那么事情就非常简单了,大部分情况下需要覆盖以下方法
    void initializeGL();
    void resizeGL(int w, int h);
    void paintGL();
如果需要用户交互,则重写若干Mouse函数即可。
4. QML View
与Sliverlight、Flash相比,QML似乎也没有什么突出优势,各有长短而已。QDeclarativeView可以显示一个QML文件,所有用户的行为可以在QML文件中定义,当然,我们可以通过代码控制QML文件中各种显示元素的行为。
关于QML的内容,本文也不涉及。

Qt--QMdiArea和QMdiSubWindow的基本用法

Qt--QMdiArea和QMdiSubWindow的基本用法

大多数复杂的程序,都使用MDI框架,在Qt designer中可以直接将控件MDI Area拖入使用。
QMdiArea一般使用于主窗口中,用于容纳多个子窗口QMdiSubWindow

代码如下:
mainwindow.h
复制代码
 1 #ifndef MAINWINDOW_H
 2 #define MAINWINDOW_H
 3 
 4 #include <QMainWindow>
 5 #include <QTextEdit>
 6 #include <QLabel>
 7 #include <QMdiSubWindow>
 8 
 9 namespace Ui {
10 class MainWindow;
11 }
12 
13 class MainWindow : public QMainWindow
14 {
15     Q_OBJECT
16 
17 public:
18     explicit MainWindow(QWidget *parent = 0);
19     ~MainWindow();
20 
21 private:
22     Ui::MainWindow *ui;
23     QMdiSubWindow *newwin;
24 
25 private slots:
26     void on_btnCloseAll_clicked();
27     void on_btnClose_clicked();
28     void on_btnNext_clicked();
29     void on_btnPrevious_clicked();
30     void on_btnNewWindow_clicked();
31     void on_btnRemoveWindow_clicked();
32 
33 };
34 
35 #endif // MAINWINDOW_H
复制代码


mainwindow.cpp
复制代码
 1 #include "mainwindow.h"
 2 #include "ui_mainwindow.h"
 3 
 4 MainWindow::MainWindow(QWidget *parent) :
 5     QMainWindow(parent),
 6     ui(new Ui::MainWindow)
 7 {
 8     ui->setupUi(this);
 9 
10     //window1
11     QTextEdit *window1 = new QTextEdit;
12     window1->setHtml("C");
13     ui->mdiArea->addSubWindow(window1);     //将window1放进mdiArea框架
14 
15     //window2
16     QTextEdit *window2 = new QTextEdit;
17     window2->setHtml("C++");
18     ui->mdiArea->addSubWindow(window2);
19 
20     //window3
21     QTextEdit *window3 = new QTextEdit;
22     window3->setHtml("Java");
23     ui->mdiArea->addSubWindow(window3);
24 
25     //window4
26     QTextEdit *window4 = new QTextEdit;
27     window4->setHtml("Hello World");
28     ui->mdiArea->addSubWindow(window4);
29 
30     ui->mdiArea->cascadeSubWindows();   //SubWindows重叠排列
31 
32     connect(ui->pushButton_6,SIGNAL(clicked()),this,SLOT(on_btnPrevious_clicked()));
33     connect(ui->pushButton_7,SIGNAL(clicked()),this,SLOT(on_btnNext_clicked()));
34     connect(ui->pushButton_8,SIGNAL(clicked()),this,SLOT(on_btnClose_clicked()));
35     connect(ui->pushButton_9,SIGNAL(clicked()),this,SLOT(on_btnCloseAll_clicked()));
36     connect(ui->pushButton_10,SIGNAL(clicked()),this,SLOT(on_btnNewWindow_clicked()));
37     connect(ui->pushButton_11,SIGNAL(clicked()),this,SLOT(on_btnRemoveWindow_clicked()));
38 }
39 
40 MainWindow::~MainWindow()
41 {
42     delete ui;
43 }
44 
45 void MainWindow::on_btnCloseAll_clicked()
46 {
47     ui->mdiArea->closeAllSubWindows();
48 }
49 
50 void MainWindow::on_btnClose_clicked()
51 {
52     ui->mdiArea->closeActiveSubWindow();
53 }
54 
55 void MainWindow::on_btnNext_clicked()
56 {
57     ui->mdiArea->activateNextSubWindow();
58 }
59 
60 void MainWindow::on_btnPrevious_clicked()
61 {
62     ui->mdiArea->activatePreviousSubWindow();
63 }
64 
65 void MainWindow::on_btnNewWindow_clicked()
66 {
67     newwin = new QMdiSubWindow;
68     newwin->setWindowTitle("test");
69     newwin->setWidget(&QLabel("hey"));
70     newwin->setAttribute(Qt::WA_DeleteOnClose);
71     newwin->resize(200,200);
72     ui->mdiArea->addSubWindow(newwin);
73     newwin->show();     //在非构造函数不加show(),不显示
74     //setActiveSubWindow(QMdiSubWindow *window);     设置active窗口
75 }
76 
77 void MainWindow::on_btnRemoveWindow_clicked()
78 {
79     ui->mdiArea->removeSubWindow(ui->mdiArea->currentSubWindow());   //remove 当前窗口
80 }
复制代码

Demo:

上图中的子窗口就是QMdiSubWindow窗口

QMdiArea类的函数解析:
QMdiSubWindow *addSubWindow(QWidget *widget, Qt::WindowFlags flags = Qt::WindowFlags());            //在MDI区域中添加SubWindow子窗口。
void removeSubWindow(QWidget *widget);                                        //删除MDI区域中SubWindow子窗口
void setBackground(const QBrush &background);                                   //设置MDI区域的背景,默认为灰色
void setActivationOrder(WindowOrder order);                                        //设置激活顺序,默认以创建先后激活,槽函数中有调用
void setOption(AreaOption option, bool on = true);                                //现只有一个选项,即创建子窗口,窗口不充满这个区域,默认是充满的    
void setViewMode(ViewMode mode);                                                    //设置视口模式,默认area中很多小窗口,也可以是有tabBar形式的,设置tab的函数,都需要先开启这个                                                
void setDocumentMode(bool enabled);                                                   //设置文档模式
void setTabsClosable(bool closable);                                                       //默认为否。设置为true时,tab上会出现一个关闭的小按钮
void setTabsMovable(bool movable);                                                      //设置是否可移动,默认为false,可以移动时,可拖动tab在tabBar上移动
void setTabShape(QTabWidget::TabShape shape);                                  //设置tab的形状,默认长方形,也可以是梯形
void setTabPosition(QTabWidget::TabPosition position);                           //设置tabBar的方位,有东南西北四方位

void activateNextSubWindow();                                                     //act下一个子窗口
void activatePreviousSubWindow();                                                //act上一个子窗口
void closeActiveSubWindow();                                                       //关闭active的子窗口
void closeAllSubWindows();                                                          //关闭所有子窗口
void cascadeSubWindows();                                                          //MDI区域内的所有子窗口重叠排列
void tileSubWindows();                                                                 //将所有子窗口在MDI区域内排列整齐
void setActiveSubWindow(QMdiSubWindow *window);                     //设置active窗口为window

void subWindowActivated(QMdiSubWindow *window);                     //signals信号,为切换激活的子窗口时发出的信号

enum QMdiArea::WindowOrder :
QMdiArea::CreationOrder   0   按创建时的先后顺序
QMdiArea::StackingOrder   1   堆叠顺序
QMdiArea::ActivationHistoryOrder   2   按激活历史前后顺序

enum QMdiArea::ViewMode :
QMdiArea::SubWindowView   0   以小窗口形式显示(默认)
QMdiArea::TabbedView   1   不仅可小窗口,而且形成tabBar

enum QTabWidget::TabShape :
QTabWidget::Rounded   0   tab形状为方形,默认
QTabWidget::Triangular   1   tab形状为梯形

enum QTabWidget::TabPosition :
QTabWidget::North   0   tab在上方显示
QTabWidget::South   1   tab在下方
QTabWidget::West   2   tab在左方
QTabWidget::East   3   tab在右方

Qt--Qmainwindow主窗口及其主要组成部分

Main Window and Related Classes

动作类,用于当做一个菜单项或工具项插入菜单或工具栏
动作组,用于管理多个动作,设置它们之间的互斥性等
部件动作,继承自QAction,用于将小部件插入菜单或工具栏
悬浮部件,程序运行后可鼠标拖动的部件
主窗口,是其它部件的容器
子区域,加到QMainWindow中,用于放置多个QMdiSubWindow子窗口
子窗口
菜单
菜单栏,存放多个菜单
管理顶层窗口尺寸,一般位于软件的右下角,状态栏最右边,鼠标可拖动它改变窗口大小
状态栏
工具栏
以QMainWindow为中心,构成了传统界面的各部分,现将它们拖在一起记录。
以rar压缩软件界面为例,各部分组成如下:
最上一行,叫菜单栏,由“文件”、“命令”等菜单组成,“选项”菜单已点击,弹出很多菜单项,Qt中用动作类QAction来表示菜单项。即QAction构成了菜单,菜单构成了菜单条,QAction可加入文字,图片等构成漂亮的菜单项。QDockWidget 悬浮部件较特殊,它在程序运行时,拖动可改变其位置。
——————————————————————————————————————————————————————————————————
建立步骤:
为了构建传统界面,需要在建立工程某步时选择继承类,如下图。
建成后,ui文件如下,“在这里输入”即是要求我们创建菜单,菜单栏下面一层即是默认的工具栏,没有添加动作,所以很细小(最左方有一个小点)
双击“在这里输入后”,可以写入文字,如下图,输入了创建了常用的“文件”。在下方五个按钮处的第一个新建一个动作,可以指定动作的名称,快捷键等,建完后,将它拖动到菜单或工具栏。
以下是效果图:
这时,只要将这个“动作”的“触发”信号连接到某个槽函数后,点击该菜单项或工具栏上的“新建”,就会执行槽函数。
以上就是建立一个传统界面的粗糙步骤
——————————————————————————————————————————————————————————————

QMainWindow

一个 主窗口各部分分布如图:
对比(图中中间白色大框为一个QTableWidget表格小部件):
公有函数分类如下:
复制代码
QMainWindow(QWidget * parent = 0, Qt::WindowFlags flags = 0)  
    ~QMainWindow()  
//设置菜单部分  
void    setMenuBar(QMenuBar * menuBar)//带ui文件默认是有一个菜单条的,如果设置了这个之后,则默认的被覆盖,一个MainWindow只能有一个主菜单处于最上方  
void    setMenuWidget(QWidget * menuBar)//覆盖默认菜单,用一个自定义的部件代替菜单,甚至可以用一个按钮……,比较灵活,看不惯默认菜单的,可试试这个。  
  
//工具栏部分  
void    addToolBar(Qt::ToolBarArea area, QToolBar * toolbar)//添加一个工具条,用枚举值Qt::ToolBarArea(见1)设定停靠区域,由图可见,停靠区分为上下左右四区域。  
void    addToolBar(QToolBar * toolbar)//添加一个工具条(默认紧跟上一个工具条)  
QToolBar *  addToolBar(const QString & title)  
void    addToolBarBreak(Qt::ToolBarArea area = Qt::TopToolBarArea)//添加一个Break(破裂; 间断; 或译为区域),这时,新添加的工具条将不再紧跟前一个工具条,而是另起一行。  
void    insertToolBar(QToolBar * before, QToolBar * toolbar)//在before工具条后加一个  
void    insertToolBarBreak(QToolBar * before)//添加分隔线  
void    removeToolBar(QToolBar * toolbar)  
void    removeToolBarBreak(QToolBar * before)  
void    setToolButtonStyle(Qt::ToolButtonStyle toolButtonStyle)//设置工具条上显示模式,默认只有文件,可设置成图片或文字形式(见2)  
void setIconSize(const QSize & iconSize)//设置工具条上图标大小,在上一个函数设置图标模式后有效  
  
//可停靠窗口部件  
void addDockWidget(Qt::DockWidgetArea area, QDockWidget * dockwidget)//area枚举值见3  
void addDockWidget(Qt::DockWidgetArea area, QDockWidget * dockwidget, Qt::Orientation orientation)  
void removeDockWidget(QDockWidget * dockwidget)  
void setCorner(Qt::Corner corner, Qt::DockWidgetArea area)//让四个角落(corner)中一个区域"归属于"某个区域(area),具体看最下方例子  
void setDockOptions(DockOptions options)//设置停靠选项,比如允许动画或是否允许拖放重合成一个tab选项卡类型的部件,枚举值见4  
void setTabPosition(Qt::DockWidgetAreas areas, QTabWidget::TabPosition tabPosition)//设置形成的tab位置  
void setTabShape(QTabWidget::TabShape tabShape)  
void setDocumentMode(bool enabled)  
void splitDockWidget(QDockWidget * first, QDockWidget * second, Qt::Orientation orientation)//部件拖动至处于同一区域时,默认重合形成tab,利用这个,可将它们分开  
  
//设置中间部件  
void setCentralWidget(QWidget * widget)  
QWidget * centralWidget() const  
  
//添加状态栏  
void setStatusBar(QStatusBar * statusbar)  
  
//保存窗口形状信息  
bool restoreState(const QByteArray & state, int version = 0)  
<p>QByteArray saveState(int version = 0) const  
bool restoreDockWidget(QDockWidget * dockwidget)  
  
</p>//其它  
Qt::DockWidgetArea  corner(Qt::Corner corner) const  
virtual QMenu * createPopupMenu()  
DockOptions dockOptions() const  
Qt::DockWidgetArea  dockWidgetArea(QDockWidget * dockwidget) const  
bool    documentMode() const  
QSize   iconSize() const  
bool    isAnimated() const  
bool    isDockNestingEnabled() const  
QMenuBar *  menuBar() const  
QWidget *   menuWidget() const  
QStatusBar *    statusBar() const  
QTabWidget::TabPosition tabPosition(Qt::DockWidgetArea area) const  
QTabWidget::TabShape    tabShape() const  
QList<QDockWidget *>  tabifiedDockWidgets(QDockWidget * dockwidget) const  
void    tabifyDockWidget(QDockWidget * first, QDockWidget * second)  
QWidget *   takeCentralWidget()  
Qt::ToolBarArea toolBarArea(QToolBar * toolbar) const  
bool    toolBarBreak(QToolBar * toolbar) const  
Qt::ToolButtonStyle toolButtonStyle() const  
复制代码
1,enum Qt::ToolBarArea
ConstantValue
Qt::LeftToolBarArea0x1
Qt::RightToolBarArea0x2
Qt::TopToolBarArea0x4
Qt::BottomToolBarArea0x8
Qt::AllToolBarAreasToolBarArea_Mask
Qt::NoToolBarArea0
2,enum Qt::ToolButtonStyle
ConstantValueDescription
Qt::ToolButtonIconOnly0只显示图标
Qt::ToolButtonTextOnly1Only display the text.
Qt::ToolButtonTextBesideIcon2The text appears beside the icon.
Qt::ToolButtonTextUnderIcon3文本显示在图标下方
Qt::ToolButtonFollowStyle4Follow the style.
3,enum Qt::DockWidgetArea
flags Qt::DockWidgetAreas
ConstantValue
Qt::LeftDockWidgetArea0x1
Qt::RightDockWidgetArea0x2
Qt::TopDockWidgetArea0x4
Qt::BottomDockWidgetArea0x8
Qt::AllDockWidgetAreasDockWidgetArea_Mask
Qt::NoDockWidgetArea0
4,enum QMainWindow::DockOption
flags QMainWindow::DockOptions
ConstantValueDescription
QMainWindow::AnimatedDocks0x01animated相同
QMainWindow::AllowNestedDocks0x02dockNestingEnabled相同
QMainWindow::AllowTabbedDocks0x04允许形成下方有tapBar的重合部件
QMainWindow::ForceTabbedDocks0x08Each dock area contains a single stack of tabbed dock widgets. In other words, dock widgets cannot be placed next to each other in a dock area. If this option is set, AllowNestedDocks has no effect.
QMainWindow::VerticalTabs0x10设置tabBar在竖直左方位置(默认在下方)
以rar压缩软件为例,用代码写出界面主要部分:
以下代码只是用于理解,是很不合理的。主要测试各部分小部件的位置,外观等,以及mainwidow的形状配置保存
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QAction>
#include <QMenu>
#include <QIcon>
#include <QSize>
#include <QLabel>
#include <QDockWidget>
#include <QTableWidget>
#include <QSettings>
 
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
 
    //菜单栏部分
    QMenu *menu1=ui->menuBar->addMenu("文件(&F)");
    QAction *me1_act1=menu1->addAction("打开压缩文件(O)");
    me1_act1->setShortcut(QKeySequence(tr("Ctrl+O")));
    //connect(me1_act1,SIGNAL(triggered()),……
    QAction *me1_act2=menu1->addAction("保存压缩文件副本为(V)");
    me1_act2->setIcon(QIcon("://img/sava.ico"));
    menu1->addSeparator();
    QAction *me1_act3=menu1->addAction("退出(X)");
    connect(me1_act3,SIGNAL(triggered()),this,SLOT(close()));
    ui->menuBar->addMenu("命令(&C)");
 
    //"文件"菜单部分
    QAction *tb1_act1=ui->mainToolBar->addAction(QIcon("://img/tool1.ico"),"添加");
    ui->mainToolBar->addSeparator();
    QAction *tb1_act2=ui->mainToolBar->addAction(QIcon("://img/tool2.ico"),"解压到");
    setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
    setIconSize(QSize(50,50));
 
    addToolBarBreak();
    toolBar=new QToolBar;
    toolBar->setObjectName("tb2");//设置对象名,用于保存配置
    toolBar->setToolButtonStyle(Qt::ToolButtonIconOnly);
    toolBar->setIconSize(QSize(20,20));
    addToolBar(toolBar);
    QAction *tb2_act1=toolBar->addAction(QIcon("://img/sharp.ico"),"");
 
    //添加中间主部件
    QTableWidget *tb1=new QTableWidget;
    setCentralWidget(tb1);
 
    //添加悬浮部件
    QDockWidget *dock1= new QDockWidget("上侧部件");
    addDockWidget(Qt::TopDockWidgetArea,dock1);
    QDockWidget *dock2_1= new QDockWidget("左侧部件1");
    addDockWidget(Qt::LeftDockWidgetArea,dock2_1);
    QDockWidget *dock2_2= new QDockWidget("左侧部件2");
    addDockWidget(Qt::LeftDockWidgetArea,dock2_2);
    splitDockWidget(dock2_1,dock2_2,Qt::Horizontal);
    QDockWidget *dock3= new QDockWidget("右侧部件");
    dock3->setFeatures(QDockWidget::DockWidgetVerticalTitleBar|QDockWidget::DockWidgetMovable);
    addDockWidget(Qt::RightDockWidgetArea,dock3);
    QDockWidget *dock4= new QDockWidget("下侧部件");
    addDockWidget(Qt::BottomDockWidgetArea,dock4);
    //setCorner(Qt::BottomLeftCorner,Qt::LeftDockWidgetArea);//让左下角区域归于左边停靠区域
    dock1->setObjectName("dock1");
    dock2_1->setObjectName("dock2_1");
    dock2_2->setObjectName("dock2_2");
    dock3->setObjectName("dock3");
    dock4->setObjectName("dock4");
 
    //状态栏部分
    QLabel *lbl1=new QLabel("无状态");
    ui->statusBar->addWidget(lbl1);
 
    //读取窗口及部件形状与状态
    readSettings();
 
}
void MainWindow::closeEvent(QCloseEvent *event)
{
    QSettings settings("大中华有限公司""测试软件名");
    settings.setValue("geometry", saveGeometry());
    settings.setValue("windowState", saveState());
    settings.sync();
}
void MainWindow::readSettings()
{
    QSettings settings("大中华有限公司""测试软件名");
    restoreGeometry(settings.value("geometry").toByteArray());
    restoreState(settings.value("windowState").toByteArray());
}
 
 
MainWindow::~MainWindow()
{
    delete ui;
}
  
作者:江南烟雨居
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。