label的父类是ui,获取Label和在哪个Tab没关系。
如果是界面里拉的,那界面上对象名叫什么,代码里就ui->labelXX->text();
当然你说的可能是另一种方法(仅提供思路):
获取Tab页所在的Widget:QWidget pWidget= ui->tab_2;
将widget上某一控件转成Label:QLabel pLabel = (QLabel)pWidget->childrenat(1);
取值:QString ValueStr= pLable->text();
这种方法因为是转换过去的,只适用于固定布局,容易崩溃,请谨慎使用
QT 子窗口获取父窗口指针的方法如下:
[cpp] view plain copy
qobject_cast<PhoenixDemo>(parentWidget())->uiactionPlayStop->setDisabled(true);
Qt作为一种基于 C++ 的跨平台 GUI 系统,能够提供给用户构造图形用户界面的强大功能。为了满足用户构造复杂图形界面系统的需求,Qt提供了丰富的多线程编程支持。从 22 版本开始,Qt主要从下面三个方面对多线程编程提供支持:一、构造了一些基本的与平台无关的线程类;二、提交用户自定义事件的 Thread-safe方式;三、多种线程间同步机制,如信号量,全局锁。这些都给用户提供了极大的方便。不过,在某些情况下,使用定时器机制能够比利用 Qt本身的多线程机制更方便地实现所需要的功能,同时也避免了不安全的现象发生。本文不仅对 Qt中的多线程支持机制进行了讨论,还着重探讨了利用定时器机制模拟多线程编程的方法。
1、系统对多线程编程的支持
不同的平台对 Qt 的多线程支持方式是不同的。当用户在 Windows *** 作系统上安装 Qt 系统时,线程支持是编译器的一个选项,在 Qt 的 mkfiles 子目录中包括了不同种类编译器的编译文件,其中带有 -mt 后缀的文件才是支持多线程的。
而在 Unix *** 作系统中,线程的支持是通过在运行 configure 脚本文件时添加 -thread选项加入的。安装过程将创建一个独立的库,即libqt-mt,因此要支持多线程编程时,必须与该库链接(链接选项为-lqt-mt),而不是与通常的 Qt 库(-lqt)链接。
另外,无论是何种平台,在增加线程支持时都需要定义宏QT_THREAD_SUPPORT(即增加编译选项-DQT_THREAD_SUPPORT)。在 Windows *** 作系统中,这一点通常是在qconfigh 文件中增加一个选项来实现的。而在 Unix 系统中通常添加在有关的 Makefile 文件中。
2、Qt中的线程类
在Qt 系统中与线程相关的最重要的类当然是 QThread 类,该类提供了创建一个新线程以及控制线程运行的各种方法。线程是通过QThread::run() 重载函数开始执行的,这一点很象 Java 语言中的线程类。在 Qt 系统中,始终运行着一个GUI主事件线程,这个主线程从窗口系统中获取事件,并将它们分发到各个组件去处理。在 QThread类中还有一种从非主事件线程中将事件提交给一个对象的方法,也就是 QThread::postEvent()方法,该方法提供了 Qt 中的一种Thread-safe 的事件提交过程。提交的事件被放进一个队列中,然后 GUI主事件线程被唤醒并将此事件发给相应的对象,这个过程与一般的窗口系统事件处理过程是一样的。值得注意的是,当事件处理过程被调用时,是在主事件线程中被调用的,而不是在调用QThread::postEvent 方法的线程中被调用。比如用户可以从一个线程中迫使另一个线程重画指定区域:
QWidget mywidget;
QThread::postEvent(mywidget, new QPaintEvent(QRect(0,0,100,100)));
然而,只有一个线程类是不够的,为编写出支持多线程的程序,还需要实现两个不同的线程对共有数据的互斥访问,因此 Qt 还提供了 QMutex类,一个线程在访问临界数据时,需要加锁,此时其他线程是无法对该临界数据同时加锁的,直到前一个线程释放该临界数据。通过这种方式才能实现对临界数据的原子 *** 作。
除此之外,还需要一些机制使得处于等待状态的线程在特定情况下被唤醒。QWaitCondition 类就提供了这种功能。当发生特定事件时,QWaitCondition 将唤醒等待该事件的所有线程或者唤醒任意一个被选中的线程。
3、用户自定义事件在多线程编程中的应用
在 Qt 系统中,定义了很多种类的事件,如定时器事件、鼠标移动事件、键盘事件、窗口控件事件等。通常,事件都来自底层的窗口系统,Qt 的主事件循环函数从系统的事件队列中获取这些事件,并将它们转换为 QEvent,然后传给相应的 QObjects 对象。
除此之外,为了满足用户的需求,Qt 系统还提供了一个 QCustomEvent 类,用于用户自定义事件,这些自定义事件可以利用QThread::postEvent() 或者QApplication::postEvent() 被发给各种控件或其他 QObject实例,而 QWidget 类的子类可以通过 QWidget::customEvent()事件处理函数方便地接收到这些自定义的事件。需要注意的是:QCustomEvent 对象在创建时都带有一个类型标识 id以定义事件类型,为了避免与 Qt 系统定义的事件类型冲突,该 id 值应该大于枚举类型 QEvent::Type 中给出的 "User" 值。
在下面的例子中,显示了多线程编程中如何利用用户自定义事件类。
UserEvent类是用户自定义的事件类,其事件标识为3467Array8,显然不会与系统定义的事件类型冲突。
class UserEvent : public QCustomEvent //用户自定义的事件类
{
public:
UserEvent(QString s) : QCustomEvent(3467Array8), sz(s) { ; }
QString str() const { return sz; }
private:
QString sz;
};
UserThread类是由QThread类继承而来的子类,在该类中除了定义有关的变量和线程控制函数外,最主要的是定义线程的启动函数UserThread::run(),在该函数中创建了一个用户自定义事件UserEvent,并利用QThread类的postEvent函数提交该事件给相应的接收对象。
class UserThread : public QThread //用户定义的线程类
{
public:
UserThread(QObject r, QMutex m, QWaitCondition c);
QObject receiver;
}
void UserThread::run() //线程类启动函数,在该函数中创建了一个用户自定义事件
{UserEvent re = new UserEvent(resultstring);
QThread::postEvent(receiver, re);
}
UserWidget类是用户定义的用于接收自定义事件的QWidget类的子类,该类利用slotGo()函数创建了一个新的线程recv(UserThread类),当收到相应的自定义事件(即id为3467Array8)时,利用customEvent函数对事件进行处理。
void UserWidget::slotGo() //用户定义控件的成员函数
{ mutexlock();
if (! recv)
recv = new UserThread(this, &mutex, &condition);
recv->start();
mutexunlock();
}
void UserWidget::customEvent(QCustomEvent e) //用户自定义事件处理函数
{ if (e->type()==3467Array8)
{
UserEvent re = (UserEvent ) e;
newstring = re->str();
}
}
在这个例子中,UserWidget对象中创建了新的线程UserThread,用户可以利用这个线程实现一些周期性的处理(如接收底层发来的消息等),一旦满足特定条件就提交一个用户自定义的事件,当UserWidget对象收到该事件时,可以按需求做出相应的处理,而一般情况下,UserWidget对象可以正常地执行某些例行处理,而完全不受底层消息的影响。
4、利用定时器机制实现多线程编程
为了避免Qt系统中多线程编程带来的问题,还可以使用系统中提供的定时器机制来实现类似的功能。定时器机制将并发的事件串行化,简化了对并发事件的处理,从而避免了thread-safe方面问题的出现。
在下面的例子中,同时有若干个对象需要接收底层发来的消息(可以通过Socket、FIFO等进程间通信机制),而消息是随机收到的,需要有一个GUI主线程专门负责接收消息。当收到消息时主线程初始化相应对象使之开始处理,同时返回,这样主线程就可以始终更新界面显示并接收外界发来的消息,达到同时对多个对象的控制;另一方面,各个对象在处理完消息后需要通知GUI主线程。对于这个问题,可以利用第3节中的用户自定义事件的方法,在主线程中安装一个事件过滤器,来捕捉从各个对象中发来的自定义事件,然后发出信号调用主线程中的一个槽函数。
另外,也可以利用Qt中的定时器机制实现类似的功能,而又不必担心Thread-safe问题。下面就是有关的代码部分:
在用户定义的Server类中创建和启动了定时器,并利用connect函数将定时器超时与读取设备文件数据相关联:
Server:: Server(QWidget parent) : QWidget(parent)
{
readTimer = new QTimer(this); //创建并启动定时器
connect(readTimer, SIGNAL(timeout()), this, SLOT(slotReadFile())); //每当定时器超时时调用函数slotReadFile读取文件
readTimer->start(100);
}
slotReadFile函数负责在定时器超时时,从文件中读取数据,然后重新启动定时器:
int Server::slotReadFile() // 消息读取和处理函数
{
readTimer->stop(); //暂时停止定时器计时
ret = read(file, buf ); //读取文件
if(ret == NULL)
{ readTimer->start(100); //当没有新消息时,重新启动定时器
return(-1);
}
else
根据buf中的内容将消息分发给各个相应的对象处理……;
readTimer->start(100); //重新启动定时器
}
在该程序中,利用了类似轮循的方式定时对用户指定的设备文件进行读取,根据读到的数据内容将信息发送到各个相应的对象。用户可以在自己的GUI主线程中创建一个Server类,帮助实现底层的消息接收过程,而本身仍然可以处理诸如界面显示的问题。当各个对象完成处理后,通过重新启动定时器继续进行周期性读取底层设备文件的过程。当然,这种方法适合于各对象对事件的处理时间较短,而底层设备发来消息的频率又相对较慢的情况。在这种情况下,上述方法完全可以满足用户的需求,而又避免了处理一些与线程并发有关的复杂问题。
当然,利用定时器机制实现多线程编程在某些方面具有一定的局限性,有关到底如何实现多线程编程,如何编写出效率更高的代码,还有待于开发者进一步研究和探讨。
在 Qt 中,我们将窗口和控件统称为部件(Widget)
窗口是指程序的整体界面,可以包含标题栏、菜单栏、工具栏、关闭按钮、最小化按钮、最大化按钮等。
控件是指按钮、复选框、文本框、表格、进度条等这些组成程序的基本元素。一个程序可以有多个窗口,一个窗口也可以有多个控件。
QWidget 是所有用户界面元素的基类,窗口和控件都是直接或间接继承自 QWidget,QMainWindow、QWidget、QDialog 三个类就是用来创建窗口的,可以直接使用也可以继承后再使用。
QMainWindow 窗口可以包含菜单栏、工具栏、状态栏、标题栏等,是最常见的窗口形式,可以作为GUI程序的主窗口。
QDialog 是对话框窗口的基类。对话框主要用来执行短期任务,或与用户进行互动,它可以是模态的也可以是非模态的。QDialog 没有菜单栏、工具栏、状态栏等。
这里我们先看QMainWindow
主窗口及其主要组成部分
以QMainWindow为中心,构成了传统界面的各部分,以普通window上的文件夹为例。
最上一行,叫菜单栏,由“文件”、“编辑”等菜单组成,“帮助”菜单已点击,d出菜单选项项,Qt中用动作类QAction来表示菜单选项。即QAction构成了菜单,菜单构成了菜单栏,QAction可加入文字,等构成漂亮的菜单项。QDockWidget悬浮部件较特殊,它在程序运行时,拖动可改变其位置。
工程建立选择继承类,如下图。
建成后,ui文件如下,“在这里输入”即是要求我们创建菜单,菜单栏下面一层即是默认的工具栏,很细的一横条,没有添加动作,所以很细小(最左方有一个小点)。
双击“在这里输入后”,可以写入文字,如下图,输入了创建了常用的“文件”。在下方五个按钮处的第一个新建一个动作,可以指定动作的名称,快捷键等,建完后,将它拖动到菜单或工具栏。
以下是效果图:
这时,只要将这个“动作”的“触发”信号连接到某个槽函数后,点击该菜单项或工具栏上的“新建”,就会执行槽函数。
一个 主窗口各部分分布如图:
公有函数主要部分如下:
toolbararea类型是qflags<toolbararea>的typedef。它存储一个或多个toolbararea值。
工具按钮的样式,描述按钮的文本和图标应如何显示。
flags Qt::DockWidgetAreas
dockWidgetAreas类型是qFlags<dockWidgetArea>的typedef。它存储一个或多个DockWidgetArea值。
flags QMainWindow::DockOptions
此枚举包含指定qmainwindow的停靠行为的标志。
上一个例子中我们使用了窗口的形状保存和恢复,这里主要使用geometry属性保存和恢复窗口的几何形状。在Windows中,基本上是存储QWindow::geometry()的结果,并在下次会话调用show()之前,调用QWindow::setGeometry()。
在X11中,这可能无法工作,因为一个不可见的窗口没有边框。后来窗口管理器将装饰窗口。当这种情况发生时,窗口朝向屏幕的底部/右下角移动取决于装饰框的大小。虽然X11提供了一种方法来避免这种转变,有些窗口管理器仍无法实现此功能。
当使用Qt Widgets时,Qt提供了保存和恢复一个窗口部件的几何形状和状态的函数。QWidget::saveGeometry()保存窗口的尺寸和最大化/全屏状态,而QWidget::restoreGeometry()用来恢复它。恢复函数还检查恢复几何形状是否超出可用的屏幕几何形状,如果超过了,则会适当地进行修改。
保存/恢复几何形状的方式有两种:
1、保存/恢复geometry()
2、保存/恢复pos()、size()
一般情况下,在程序退出之前,保存最后一次的几何形状和位置。
在show()之前,然后读取上次保存的信息,一般在构造函数中调用。
另一种方式是同时存储pos()和size(),并在show()之前调用QWidget::resize()和move() 。
一般情况下,在程序退出之前,保存最后一次的几何形状和位置。常在closeEvent()中调用。
在show()之前,然后读取上次保存的信息,一般在构造函数中调用。
以上就是关于QT中的tabwidget有几个tab页,每个tab页中有label控件,怎么在函数中获取某个tab页中的label里的值全部的内容,包括:QT中的tabwidget有几个tab页,每个tab页中有label控件,怎么在函数中获取某个tab页中的label里的值、qt怎么获取动态控件的指针、QT不同平台对线程如何支持和实现等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)