一、信号槽机制下,只有头文件中加入了Q_OBJECT,你才能使用QT中的signal和slot机制。
Q:子类继承父类时,子类头文件未加入Q_OBJECT时,可以构建纯虚函数来实现子类得信号槽机制。
A:
父类函数baseWave类头文件定义纯虚函数setWavepage;
class baseWave : public QWidget
{
Q_OBJECT
public:
explicit baseWave(QWidget *parent = 0);
~baseWave();
void virtual setWavepage() = 0;
}
子类函数waveFirst类头文件定义,必须实现setWavepage函数;
class waveFirst : public baseWave
{
Q_OBJECT
public:
explicit waveFirst (QWidget *parent = 0);
~waveFirst ();
void setWavepage();
}
当子类需要实现信号槽机制时,子类函数waveFirst类头文件定义,必须实现setWavepage函数;
connect(timerTime, SIGNAL(timeout()), this, SLOT(UpdateTime()));
*********************************分割线 Q2********************************************************
在设计界面时,遇到在一个界面时,需要多级按钮的切换。实例中,有五个按钮,实现界面的8个功能实现。8个功能分为具体的四类,每类分别实现两种功能(必须为四类)。
案列描述:
触发按钮1(BT1)时,按钮界面能实现功能1和功能2;
触发按钮2(BT2)时,按钮界面能实现功能3和功能4;
触发按钮3(BT3)时,按钮界面能实现功能5和功能6;
触发按钮4(BT4)时,按钮界面能实现功能7和功能8;
触发按钮5(BT5)时,按钮界面能实现返回一级BT界面;
界面文件UI:
界面头文件定义,自定义槽函数,枚举BUTTON的LEVEL,定义变量m_button_level及其get和set函数:
class MainWindow : public QMainWindow
{
Q_OBJECT
enum {
MENU_BUTTON_INIT = 0x00,
MENU_BUTTON_FIRST = 0x01,
MENU_BUTTON_SECOND= 0x02,
MENU_BUTTON_THRID = 0x03,
MENU_BUTTON_FOUR = 0x04,
};
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
int button_level() const;
void setButton_level(int button_level);
private slots:
void on_pushButton_clicked();
void on_pushButton_2_clicked();
void on_pushButton_3_clicked();
void on_pushButton_4_clicked();
void on_pushButton_5_clicked();
private:
Ui::MainWindow *ui;
int m_button_level;
};
cpp文件的设计:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
m_button_level = MENU_BUTTON_INIT;
ui->pushButton->setText("按钮1.1");
ui->pushButton_2->setText("按钮2.1");
ui->pushButton_3->setText("按钮3.1");
ui->pushButton_4->setText("按钮4.1");
ui->pushButton_5->setText("返回");
ui->pushButton_5->setEnabled(false);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
if(button_level() == MENU_BUTTON_INIT)
{
ui->pushButton->setText("功能1");
ui->pushButton_2->setText("功能2");
ui->pushButton_3->setText("");
ui->pushButton_4->setText("");
ui->pushButton_5->setText("返回");
ui->pushButton->setEnabled(true);
ui->pushButton_2->setEnabled(true);
ui->pushButton_3->setEnabled(false);
ui->pushButton_4->setEnabled(false);
ui->pushButton_5->setEnabled(true);
setButton_level(MENU_BUTTON_FIRST);
}
else if(button_level() == MENU_BUTTON_FIRST)
{
qDebug() << "send function 1!";
}
else if(button_level() == MENU_BUTTON_SECOND)
{
qDebug() << "send function 3!";
}
}
void MainWindow::on_pushButton_2_clicked()
{
if(button_level() == MENU_BUTTON_INIT)
{
ui->pushButton->setText("功能3");
ui->pushButton_2->setText("功能4");
ui->pushButton_3->setText("");
ui->pushButton_4->setText("");
ui->pushButton_5->setText("返回");
ui->pushButton->setEnabled(true);
ui->pushButton_2->setEnabled(true);
ui->pushButton_3->setEnabled(false);
ui->pushButton_4->setEnabled(false);
ui->pushButton_5->setEnabled(true);
setButton_level(MENU_BUTTON_SECOND);
}
else if(button_level() == MENU_BUTTON_FIRST)
{
qDebug() << "send function 2!";
}
else if(button_level() == MENU_BUTTON_SECOND)
{
qDebug() << "send function 4!";
}
else if(button_level() == MENU_BUTTON_THRID)
{
qDebug() << "send function 5!";
}
}
void MainWindow::on_pushButton_3_clicked()
{
if(button_level() == MENU_BUTTON_INIT)
{
ui->pushButton->setText("");
ui->pushButton_2->setText("功能5");
ui->pushButton_3->setText("功能6");
ui->pushButton_4->setText("");
ui->pushButton_5->setText("返回");
ui->pushButton->setEnabled(false);
ui->pushButton_2->setEnabled(true);
ui->pushButton_3->setEnabled(true);
ui->pushButton_4->setEnabled(false);
ui->pushButton_5->setEnabled(true);
setButton_level(MENU_BUTTON_THRID);
}
else if(button_level() == MENU_BUTTON_THRID)
{
qDebug() << "send function 6!";
}
else if(button_level() == MENU_BUTTON_FOUR)
{
qDebug() << "send function 7!";
}
}
void MainWindow::on_pushButton_4_clicked()
{
if(button_level() == MENU_BUTTON_INIT)
{
ui->pushButton->setText("");
ui->pushButton_2->setText("");
ui->pushButton_3->setText("功能7");
ui->pushButton_4->setText("功能8");
ui->pushButton_5->setText("返回");
ui->pushButton->setEnabled(false);
ui->pushButton_2->setEnabled(false);
ui->pushButton_3->setEnabled(true);
ui->pushButton_4->setEnabled(true);
ui->pushButton_5->setEnabled(true);
setButton_level(MENU_BUTTON_FOUR);
}
else if(button_level() == MENU_BUTTON_FOUR)
{
qDebug() << "send function 8!";
}
}
void MainWindow::on_pushButton_5_clicked()
{
if(button_level() != MENU_BUTTON_INIT)
{
ui->pushButton->setText("按钮1.1");
ui->pushButton_2->setText("按钮2.1");
ui->pushButton_3->setText("按钮3.1");
ui->pushButton_4->setText("按钮4.1");
ui->pushButton_5->setText("返回");
ui->pushButton->setEnabled(true);
ui->pushButton_2->setEnabled(true);
ui->pushButton_3->setEnabled(true);
ui->pushButton_4->setEnabled(true);
ui->pushButton_5->setEnabled(true);
setButton_level(MENU_BUTTON_INIT);
}
}
int MainWindow::button_level() const
{
return m_button_level;
}
void MainWindow::setButton_level(int button_level)
{
m_button_level = button_level;
}
按钮操作显示图:

输出Debug:
send function 1!
send function 2!
send function 3!
send function 4!
send function 5!
send function 6!
send function 8!
send function 7!
########################要点#######################
关键在于不同功能的类区分,用宏定义,实现对于不同功能切换时,设置Level来区分。
*********************************分割线 Q3********************************************************
在应用Qt的tablewidget开发时,遇到一个页面最多显示10行,总共有60个序号需要显示,这时通过切换到不同的table的page,采用双列的显示方式,具体要求见图;(tip:tablewidget基础知识我是参照这篇文章的)
60个序号对应着,每个的索引、值、属性;每页显示20个序号,可以通过3的页面切换显示所有序号。通过button来触发页面切换,和每个索引值和属性的改变,且值设置了输入范围;(插入Line Edit参考了这边文章-- m沉默01的Qt之QTableWidget详细使用,NICE,很详细!!)
头文件:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#define KEY_NUM_0 (Qt::Key_0) // 0
#define KEY_NUM_1 (Qt::Key_1) // 1
#define KEY_NUM_2 (Qt::Key_2) // 2
#define KEY_NUM_3 (Qt::Key_3) // 3
#define KEY_NUM_4 (Qt::Key_4) // 4
#define KEY_NUM_5 (Qt::Key_5) // 5
#define KEY_NUM_6 (Qt::Key_6) // 6
#define KEY_NUM_7 (Qt::Key_7) // 7
#define KEY_NUM_8 (Qt::Key_8) // 8
#define KEY_NUM_9 (Qt::Key_9) // 9
#define KEY_UP (Qt::Key_Up)
#define KEY_DOWN (Qt::Key_Down)
#define KEY_LEFT (Qt::Key_Left)
#define KEY_RIGHT (Qt::Key_Right)
#define KEY_CONFIRM (Qt::Key_Return)
#include <QMainWindow>
#include <QTableWidget>
#include <QKeyEvent>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
void initNetWidget();
void showTableIndex(int index);
void netSelectItem(int row, int column);
void netUpdateRedeployWave(unsigned char row, unsigned char cloumn);
protected slots:
void keyPressEvent(QKeyEvent * event);
private slots:
void on_pushButton_clicked();
void on_pushButton_2_clicked();
void on_pushButton_3_clicked();
private:
Ui::MainWindow *ui;
int m_netRow;
int m_netColumn;
int m_columId;
int m_pageIndex;
};
#endif // MAINWINDOW_H
cpp文件:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
#include <QLineEdit>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
m_columId = 1;
m_pageIndex = 0;
initNetWidget();
}
MainWindow::~MainWindow()
{
delete ui;
}
//初始化tablewidget
void MainWindow::initNetWidget()
{
ui->tableWidget->setFocusPolicy(Qt::NoFocus);
ui->tableWidget->setVerticalScrollBarPolicy(
Qt::ScrollBarAlwaysOff);
ui->tableWidget->setHorizontalScrollBarPolicy(
Qt::ScrollBarAlwaysOff);
ui->tableWidget->setEditTriggers(
QAbstractItemView::NoEditTriggers);
ui->tableWidget->setSelectionMode(
QAbstractItemView::SingleSelection);
ui->tableWidget->setGridStyle(Qt::DotLine);
ui->tableWidget->horizontalHeader()->setStyleSheet(
"QHeaderView::section{background:skyblue;}");
ui->tableWidget->verticalHeader()->setVisible(false);
//设置不同页面默认选择项
m_netRow = m_pageIndex*10;
m_netColumn = 1;
netSelectItem(0,1);
showTableIndex(m_pageIndex);
}
//根据m_pageIndex的范围0-2,来显示其中10行
void MainWindow::showTableIndex(int index)
{
int tIndex = 0;
for(tIndex;tIndex < ui->tableWidget->rowCount();tIndex ++)
{
ui->tableWidget->setRowHidden(tIndex, true);
}
tIndex = index*10;
for(tIndex;tIndex <(index+1)*10;tIndex ++)
{
//显示tIndex行
ui->tableWidget->setRowHidden(tIndex, false);
//限制文本输入范围
QRegExp rx("[1-9]|[1-5][0-9]|6[0]");
QRegExpValidator *pReg = new QRegExpValidator(rx,this);
QLineEdit *line_1 = new QLineEdit();
QLineEdit *line_2 = new QLineEdit();
//lineEdit设为noFocus
line_1->setFocusPolicy(Qt::NoFocus);
line_2->setFocusPolicy(Qt::NoFocus);
line_1->setPlaceholderText("输入范围1-60:");
line_2->setPlaceholderText("输入范围1-60:");
line_1->setValidator(pReg);
line_2->setValidator(pReg);
//tablewidget item插入lineEdit
ui->tableWidget->setCellWidget(tIndex,1,line_1);
ui->tableWidget->setCellWidget(tIndex,4,line_2);
}
}
//设置默认的item索引
void MainWindow::netSelectItem(int row,int column)
{
ui->tableWidget->clearSelection();
m_netRow = row;
m_netColumn = column;
ui->tableWidget->item(row,column)->setSelected(true);
}
//键盘按键触发事件
//0-9可以选择不同的行
//上下左右切换到不同的item
void MainWindow::keyPressEvent(QKeyEvent *event)
{
switch(event->key()) {
case KEY_NUM_1:
netSelectItem(0+10*m_pageIndex,m_netColumn);
break;
case KEY_NUM_2:
netSelectItem(1+10*m_pageIndex,m_netColumn);
break;
case KEY_NUM_3:
netSelectItem(2+10*m_pageIndex,m_netColumn);
break;
case KEY_NUM_4:
netSelectItem(3+10*m_pageIndex,m_netColumn);
break;
case KEY_NUM_5:
netSelectItem(4+10*m_pageIndex,m_netColumn);
break;
case KEY_NUM_6:
netSelectItem(5+10*m_pageIndex,m_netColumn);
break;
case KEY_NUM_7:
netSelectItem(6+10*m_pageIndex,m_netColumn);
break;
case KEY_NUM_8:
netSelectItem(7+10*m_pageIndex,m_netColumn);
break;
case KEY_NUM_9:
netSelectItem(8+10*m_pageIndex,m_netColumn);
break;
case KEY_NUM_0:
netSelectItem(9+10*m_pageIndex,m_netColumn);
break;
case KEY_UP:
m_netRow =10*m_pageIndex+
(m_netRow%10+9) %10;
netSelectItem(m_netRow, m_netColumn);
break;
case KEY_DOWN:
m_netRow =10*m_pageIndex+
(m_netRow%10+1) %10;
netSelectItem(m_netRow,m_netColumn);
break;
case KEY_LEFT:
case KEY_RIGHT:
if(m_columId == 1)
{
netSelectItem(m_netRow,4);
m_columId = 4;
}
else
{
netSelectItem(m_netRow,1);
m_columId = 1;
}
break;
case Qt::Key_Enter:
case KEY_CONFIRM: //回车键来实现LineEdit与主窗口焦点的切换
if(ui->tableWidget->cellWidget(m_netRow,m_netColumn)->hasFocus())
{
this->setFocus();
}
else
{
ui->tableWidget->cellWidget(m_netRow,m_netColumn)->setFocus();
}
break;
default:
break;
}
}
//更改当前item的属性
void MainWindow::netUpdateRedeployWave(
unsigned char row,
unsigned char cloumn)
{
if(ui->tableWidget->item(row,cloumn)->text().compare(QStringLiteral("是")) == 0)
{
ui->tableWidget->item(row,cloumn)->setText(
QStringLiteral("否"));
}
else
{
ui->tableWidget->item(row,cloumn)->setText(
QStringLiteral("是"));
}
}
//更改item属性
void MainWindow::on_pushButton_clicked()
{
netUpdateRedeployWave(m_netRow,m_columId+1);
}
//bt2和bt3切换页面
void MainWindow::on_pushButton_2_clicked()
{
m_pageIndex = (m_pageIndex+2)%3;
m_netRow = m_netRow%10+10*m_pageIndex;
netSelectItem(m_netRow,m_netColumn);
showTableIndex(m_pageIndex);}
void MainWindow::on_pushButton_3_clicked()
{
m_pageIndex = (m_pageIndex+1)%3;
m_netRow = m_netRow%10+10*m_pageIndex;
netSelectItem(m_netRow,m_netColumn);
showTableIndex(m_pageIndex);
}
OK,这个基本差不多了。
运行后的界面:
文本输入可以通过Enter键来获取item的焦点,输入1-60的整数即可;回车之后还可以通过0-9来快捷访问不同的item;右侧的按键也可以翻页及修改属性值:
########################要点#######################
对tablewidget基本函数的了解;上下左右进行切换不同item时,注意不同页面的item范围不一致;在第一页时,m_pageIndex =0,item最小值 m_netRow = m_netRow%10+10*m_pageIndex;在tablewidget item插入控件时,需要设置控件的focuspolicy为NoFocus,这样不会让父类失去焦点。
*********************************分割线 Q4********************************************************
在使用QT按键时,进行按键触发响应事件,等待业务(应答)应答过程中,可以通过加入定时器过度中间过程。可能出现业务无应答,可以通过定时器超时,将状态及按键进行初始化;在定时器执行过程中,有业务应答回应,可以停止定时器,从而进入到下一个业务状态。
代码实现为:
.h文件
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QTimer>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
void InitTimer(int time=10);
private slots:
void on_bt1_clicked();
void recvMsg(int flag);
void TimerTimeOut();
private:
Ui::MainWindow *ui;
QTimer *m_timer;
int m_status;
};
#endif // MAINWINDOW_H
.cpp文件:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
#include<QKeyEvent>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
m_timer = new QTimer(this);
m_status = 0;
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::InitTimer(int time)
{
if(NULL == m_timer)
{
m_timer = new QTimer(this);
}
m_timer->setSingleShot(false);
m_timer->start(time*1000);
connect(m_timer,SIGNAL(timeout()),
this,SLOT(TimerTimeOut()));
}
void MainWindow::on_bt1_clicked()
{
if(m_status == 0)
{
InitTimer(5);
ui->bt1->setText("参数配置中");
qDebug() << "状态1下,启动定时器!";
}
else if(m_status == 1)
{
InitTimer(5);
ui->bt1->setText("取消配置中");
qDebug() << "状态2下,启动定时器!";
}
}
void MainWindow::recvMsg(int flag)
{
qDebug() << "Recv Response";
if(m_timer->isActive())
{
m_timer->stop();
qDebug() << "业务配置成功/失败!";
}
m_status = flag;
switch flag:{
case 1: //success
qDebug() << "业务配置成功!";
ui->bt1->setText("业务中");
break;
case 0: //failed
qDebug() << "业务配置失败!";
ui->bt1->setText("参数配置");
break;
defalut:
break;
}
}
void MainWindow::TimerTimeOut()
{
ui->bt1->setText("参数配置");
qDebug() << "业务配置超时,返回状态1!";
m_status = 0;
}