qt初学者往往会发现这样的一个问题——无论是我买的相关的书,还是网上博客的内容,基本全都是利用纯代码的形式来进行界面设计的。而初学者对各种控件的代码实现并不熟悉,往往在这里耗费大量时间。故本篇文章介绍了通过ui图形化界面进行设计的过程并简单梳理了一下工程的结构。
下面以ubuntu系统下的一个双窗口互相切换的简易计算器为例。效果图如下:
第一个界面的第一个标签
功能是在输入框中输入两个数,下面的显示框显示相加的结果。
第一个界面的第二个标签
功能是在输入框中输入两个数,下面的显示框显示相乘的结果。按切换按钮可切换到第二个界面。
第二个界面
功能是把第一个界面的两个运算结果的和显示在显示框中。按“返回”按钮可回到第一个界面。
下面说下具体实现步骤吧。
一.创建工程
由于我们要实现两个窗口之间的互相切换,故我们要创建两个类。首先建立工程以及第一个类:
打开Qt creater, File->New file or project,project选择applications,右边目录选择Qt GUI Application,下一步后为工程命名,这里我们就命名calculator,下一步选择编译及调试工具,再下一步选择窗口类型,这里就选择QMainWindow吧,类的命名为calculator,注意勾选Generate Form,这样工程中才会有ui界面,最后一步不管,直接finish。至此,我们已经完成了工程及第一个类的创建。
下面创建第二个类。之前说过,相关书籍和博客上普遍都是采用代码的形式来创建第二个类的,相当的麻烦。这里我们利用图形化界面直接创建第二个类:右键工程名calculator,选择Add New,在弹出的对话框中,Files and Classes选择Qt,右边选择Qt Designer Form Class,下一步的模板就选择MainWindow吧。下一步命名extendedwindow,最后一步finish。至此我们就创建了工程中的第二个类。接着,在main.cpp包含头文件“extendedwindow.h”并定义新的对象e——extendedwindow e;是不是比用代码创建方便很多啊。
完成以上步骤后,你的projects栏中应该有如下的树形图界面——
二.接下来我们利用ui界面完成界面的设计,具体功能的实现将放在步骤3中讲解。
先编辑第一个窗口即calculator这个窗口,双击calculator.ui进入图形化设计界面,从左边的控件栏中找到containers下的tab widget,把他拖出来放到界面中,再拖出两个Line Edit和一个Text Browser以及一个Lable到tab widget的第一个tab中,右上角有一个树形图栏记录着当前窗口中的对象和类,在这里修改创建的对象的名字,提高可读性(如图)。
接着利用界面上方的对齐工具进行对齐(如图)
第二个标签里的内容也同样操作。每个控件的大小可以通过拖动改变。最后再拖动一个push button到tab widget控件外部。最终的效果图如之前展示的界面一所示。
完成了第一个窗口的设计,接下来完成第二个窗口的设计。需要用到的控件是text browser和push button,过程这里就不说了。
三.功能的实现
Qt各对象之间的通信是通过信号与槽来实现的。故不要想着用对象a去访问对象b的私有成员。带参数的信号完全可以实现数据的传递。信号与槽机制的特点就是可以使得对象在彼此完全不了解的情况下将他们的行为联系起来。对于这句话的理解是:各个类在定义时完全不需要考虑他与其他类可能会有什么联系,各自定义各自的即可。当需要把几个对象联系起来的时候,临时写一句connect就可以达成目的。
由于本文的重点在于介绍通过ui图形化界面实现界面的设计,对于计算器计算的相关内容就不进行叙述了,相关代码将在最后贴出。这个部分我们只讲下对象是怎么通过信号与槽来进行通信的:
3.1控件对象与窗口对象之间的通信
选中tab1中的上方的那个line edit,右键,选择go to slot,接着会弹出一个对话框,里面是各种类型的line edit所属的QLineEdit类中的信号成员。通过这些信号的名字就可以猜到它的功能,如editingFinished(),它表示如果用户对这个行输入框的操作结束了(包括失去焦点和回车这两种形式),则行输入框这个对象将发射这个信号。
这里我们选择textEdited(),则界面自动跳到calculator.cpp文件,并且这个文件中已经自动创建了一个槽函数
void calculator::on_number1_textEdited(const QString &arg1)
经过观察,我们发现这是一个属于calculator类的槽函数。事实上,如果你现在打开calculator.h文件,你会发现Qt creater已经自动帮你在类的定义中加上了刚刚那个槽函数。除此之外,软件还自动帮你完成了这两个对象信号与槽的连接并将这段代码隐藏了起来(具体在哪不知道)。当你编辑行输入框时,信号被发送给calculator定义的对象的槽,槽函数执行特定的功能。需要强调的是,函数
QObject::connect ( const QObject * sender, const char* signal, const QObject * receiver, const char* member )
的第一个参数和第三个参数是对象的地址而不是类的地址。而窗口对应的对象的定义是在main.cpp中进行的
calculator w;
参数写法应是&number1(number1是我对那个行输入框的命名,可在右上角的树形图栏中查看)和&w。这里要通过第一个输入框读取得到的数(字符型),在槽函数中写如下代码:
QString n1=ui->number1->text();
num1=n1.toDouble();
需要解释的是:
①:
这里的ui代表的就是caltulator.ui这整个图形化界面。它的定义在头文件calculator.h里面,它是类calculator的一个成员
private:Ui::calculator *ui;
可见,ui是指向类calculator对象的一个指针。利用它可以对ui图形化界面里的控件方便地进行访问。具体方法为ui->…。(ui后输入小数点“.”,软件会自动改成->)。细心的人可能会发现,calculator.h和extendedwindow.h中都有ui,而各cpp文件中也都有ui,他们指向不同的对象,编译器却没报错。具体原因我也不知道,总之利用他们可以访问各自的图形化界面。
②:
通过输入框得到的内容是字符型的,故还需要用所示代码将其转换成double型数据。函数定义可在Qt Assistant中查找。
3.2 两个窗口对象之间的通信
两个窗口之间的通信需要我们手动去写所有的代码。思路如下:在类calculator和extendedWindow中各定义一个信号和槽函数(带不带参数视情况而定),用于他们之间的通信。在主函数中将两组信号与槽联系起来。通过软件自动建立的连接,让窗口一中按钮对象与类calculator对象w通信,槽函数收到信号后,隐藏第一个窗口,再让其主动发送信号给类extendedwindow对象e,让第二个窗口显示出来。
//两组信号与槽的联系
QObject::connect(&w,SIGNAL(w2e(double,double)),&e,SLOT(receive(double,double)));
QObject::connect(&e,SIGNAL(e2w()),&w,SLOT(receive()));
//窗口一控件对象的槽函数
void calculator::on_switch_2_clicked()
{this->hide();emit w2e(Result1,Result2);
}
//类extendedwindow槽函数
void extendedWindow::receive(double n1,double n2)
{this->show();QString n=QString::number((n1+n2),'g',6);ui->textBrowser->setText(n);
}
//窗口二控件对象的槽函数
void extendedWindow::on_pushButton_clicked()
{this->hide();emit e2w();
}
//类calculator对象的槽函数
void calculator::receive()
{this->show();
}
至此,功能的实现部分全部讲完
下面贴出各文件的代码,ui界面需自己设计:
//calculator.h
#ifndef CALCULATOR_H
#define CALCULATOR_H#include <QMainWindow>
#include <QString>namespace Ui {
class calculator;
}class calculator : public QMainWindow
{Q_OBJECTpublic:explicit calculator(QWidget *parent = 0);~calculator();private slots:void on_number1_textEdited(const QString &arg1);void on_number2_textEdited(const QString &arg1);void on_number2_editingFinished();void on_number1_2_textEdited(const QString &arg1);void on_number2_2_textEdited(const QString &arg1);void on_number2_2_editingFinished();void on_switch_2_clicked();void receive();signals:void w2e(double,double);private:Ui::calculator *ui;QString input;double num1,num2,num3,num4,Result1,Result2;
};#endif // CALCULATOR_H//extendedwindow.h
#ifndef EXTENDEDWINDOW_H
#define EXTENDEDWINDOW_H#include <QMainWindow>namespace Ui {
class extendedWindow;
}class extendedWindow : public QMainWindow
{Q_OBJECTpublic:explicit extendedWindow(QWidget *parent = 0);~extendedWindow();public slots:void on_pushButton_clicked();void receive(double,double);signals:void e2w();
private:Ui::extendedWindow *ui;
};#endif // EXTENDEDWINDOW_H//calculator.cpp
#include "calculator.h"
#include "ui_calculator.h"calculator::calculator(QWidget *parent) :QMainWindow(parent),ui(new Ui::calculator)
{ui->setupUi(this);
}calculator::~calculator()
{delete ui;
}void calculator::on_number1_textEdited(const QString &arg1)
{QString n1=ui->number1->text();num1=n1.toDouble();}void calculator::on_number2_textEdited(const QString &arg1)
{QString n2=ui->number2->text();num2=n2.toDouble();
}void calculator::on_number2_editingFinished()
{Result1=num1+num2;QString n3=QString::number(Result1,'g',6);ui->result->setText(n3);
}void calculator::on_number1_2_textEdited(const QString &arg1)
{QString n=ui->number1_2->text();num3=n.toDouble();
}void calculator::on_number2_2_textEdited(const QString &arg1)
{QString n=ui->number2_2->text();num4=n.toDouble();
}void calculator::on_number2_2_editingFinished()
{Result2=num3*num4;QString n=QString::number(Result2,'g',6);ui->result_2->setText(n);
}void calculator::on_switch_2_clicked()
{this->hide();emit w2e(Result1,Result2);
}void calculator::receive()
{this->show();
}//extendedwindow.cpp
#include "extendedwindow.h"
#include "ui_extendedwindow.h"extendedWindow::extendedWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::extendedWindow)
{ui->setupUi(this);
}extendedWindow::~extendedWindow()
{delete ui;
}void extendedWindow::on_pushButton_clicked()
{this->hide();emit e2w();
}void extendedWindow::receive(double n1,double n2)
{this->show();QString n=QString::number((n1+n2),'g',6);ui->textBrowser->setText(n);
}//main.cpp
#include "calculator.h"
#include <QApplication>
#include "extendedwindow.h"int main(int argc, char *argv[])
{QApplication a(argc, argv);calculator w;extendedWindow e;QObject::connect(&w,SIGNAL(w2e(double,double)),&e,SLOT(receive(double,double)));QObject::connect(&e,SIGNAL(e2w()),&w,SLOT(receive()));w.setFixedSize(500,500);e.setFixedSize(500,500);w.move(500,50);e.move(500,50);e.hide();w.show();return a.exec();
}