Qt常用的按钮控件编程(六)-- QDialogButtonBox 按钮


前言

本文介绍我们系列文章QT常用控件的最后一个按钮,QDialogButtonBox按钮编程。通过这个例子,巩固QT的信号与槽知识,了解Qt5对Qt4所做的改进。由于我们的开发的软件显示和输入需要在触摸屏上进行,因此本例演示了如何弹出一个小键盘。
本例程设计是在chatgpt的帮助下完成的,编译代码经过测试通过。

感谢朋友提供的chatgpt软件,特别是其中的gpt-box桌面工具,更是我离不开的工具。感兴趣的同仁可前往一观(www.apsuai.com)。

我们的调试环境仍然是双架构Kits,编译调试在当前的ubuntu(qt5)中进行,重新编译后下载到目标arm设备(qt4)中运行。
我们的编程环境为:Ubuntu64位系统(22.04),目标架构:
(1) qt5 x86_64 架构;
(2)qt4 32位arm架构。
环境配置请参见《Qt常用的按钮控件编程(一)》第1节。


8、QDialogButtonBox按钮

QDialogButtonBox 是在 Qt 中用于显示一组标准窗口操作按钮的小部件,如“确定”、“取消”、“应用”按钮等。它可以将其中的按钮排列成横向(水平)或纵向(垂直)布局,也可以根据需要添加自定义按钮。

常用的标准按钮类型包括:

  • OK:显示“确定”按钮;
  • Cancel:显示“取消”按钮;
  • Close:显示“关闭”按钮;
  • Apply:显示“应用”按钮;
  • Reset:显示“重置”按钮;
  • Help:显示“帮助”按钮。

使用 QDialogButtonBox 控件的好处在于,它会自动以标准的方式处理按钮的布局和按键事件,可以避免手动设置布局和连接信号和槽的繁琐过程。它还可以根据窗口的样式,在样式表的作用下,呈现一致美观的界面,降低了开发的复杂度和难度。

8.1 向chatgpt提出的要求

向chatgpt提出的要求如下:
“使用Qt Creator 创建一个c++例程,项目名称"_qdialogbuttonbox" ,基类不选默认MainWindow类,而选择Widget作为基类,不要勾选“Generate form”,不使用拖取控件,控件全部采用编程。主窗口大小800*480,在主窗口上,放置一个QPushButton按钮,位于主窗口正中,点击,弹出一个对话框,对话框中有一个小键盘,可以设置ip地址和端口号,两个QDialogButtonBox,分别为确定和取消,确定后,调试打印出ip和端口。”
chatgpt根据要求给出了完整的例程,但与我希望需求的要进行些许调整:

  • 控件的布局看起来不怎么合理,做了调整;
  • 例程按照qt5完成,需要调整兼容qt4。

8.2 例程功能和程序执行效果

在主窗口上,放置一个QPushButton按钮,点击,弹出一个对话框,可以设置ip地址和端口号,两个QDialogButtonBox,分别为确定和取消,确定后,调试打印出ip和端口。

在主窗口上,放置一个QPushButton按钮,位于主窗口正中,点击,弹出一个对话框,对话框用来设置ip地址和端口号,点击ip提示和端口提示,弹出小键盘,可以设置两个QDialogButtonBox,分别为确定和取消,确定后,调试打印出ip和端口。设计一下。

程序执行效果:

  • 主界面:
    在这里插入图片描述

  • 出现设置对话框

在这里插入图片描述

  • 点击IP或Port,用弹出的小键盘输入ip地址和端口号,如下图:
    在这里插入图片描述
    输入IP地址和端口号,在终端输出区,打印出调试信息:
    在这里插入图片描述

警告信息处理

直接运行:

 ./_qdialogbuttonbox

会出现下面的警告:

Warning: Ignoring XDG_SESSION_TYPE=wayland on Gnome. Use QT_QPA_PLATFORM=wayland to run on Wayland anyway.

出现上面的警告原因是因为我们的ubuntu22.04系统默认使用Wayland作为显示服务器。而Qt框架默认使用X11作为显示服务器,将运行改为:

XDG_SESSION_TYPE=x11 ./_qdialogbuttonbox

或分两步:

export XDG_SESSION_TYPE=x11
./_qdialogbuttonbox

则警告消失。


8.3 生成项目

使用Qt Creator 创建一个c++例程,项目名称"_qdialogbuttonbox" ,不选默认MainWindow类,选择Widget作为基类,不要勾选“Generate form”,不使用拖取控件,控件全部采用编程。将两个配置好的Kits同时选上,项目新建完成如下图。(详细的项目新建过程参见:《Qt常用的按钮控件编程(一)》)。
在这里插入图片描述点击左侧的Debug选项,可以看到两个编译套件Kit,可以选择编译运行在不同平台上的可执行文件,arm-v7为arm架构的设备,使用Qt4库,而桌面则是当前ubuntu系统,使用Qt5。

8.4 代码编辑

8.4.1 修改项目文件_qdialogbuttonbox.pro

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++11

# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
    dialog.cpp \
    keypaddialog.cpp \
    main.cpp \
    widget.cpp

HEADERS += \
    dialog.h \
    keypaddialog.h \
    widget.h

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

# 根据使用的 Qt 版本设置编译条件
greaterThan(QT_MAJOR_VERSION, 4) {
    # 如果使用的是 Qt 5 或者更新版本
    message("使用的是 Qt 5版本")

} else {
    # 如果使用的是 Qt 4 或者更早的版本
    message("使用的是 Qt 4版本")
    DEFINES += QT_ARM_PLATFORM
    QMAKE_CXXFLAGS += -std=c++11
    QMAKE_CXXFLAGS += -Wno-psabi -Wno-deprecated-declarations

    LIBS += -lts

}

8.4.2 修改 main.cpp

#include "widget.h"

#include <QApplication>
#ifdef QT_ARM_PLATFORM
#include <QTextCodec>
#endif
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

#ifdef QT_ARM_PLATFORM
    //解决Qt4中文乱码
    QTextCodec::setCodecForTr(QTextCodec::codecForName("GBK"));
    QTextCodec::setCodecForTr(QTextCodec::codecForName("system"));    //若英文系统,则用GBK
    QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
    QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
#endif

    Widget w;
    w.show();
    return a.exec();
}

8.4.3 修改 widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

#include <QMainWindow>
 /* 引入 QDialogButtonBox */
 #include <QDialogButtonBox>
 /* 引入 QPuhsButton */
 #include <QPushButton>
class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();


public slots:
    void slotOpenDialog();

private:
    QPushButton *m_button;
};
#endif // WIDGET_H

8.4.4 修改 widget.cpp

#include "widget.h"
#include "dialog.h"
#include <QDebug>
Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    /* 主窗体设置位置和显示的大小 */
    this->setGeometry(0, 0, 800, 480);

    m_button = new QPushButton("设置网络参数", this);
     m_button->setFixedSize(120, 80);
     m_button->move(340, 200);

     connect(m_button, SIGNAL(clicked()), this, SLOT(slotOpenDialog()));

}

Widget::~Widget()
{
    delete m_button;
}

void Widget::slotOpenDialog()
{
    Dialog dialog(this);
    if (dialog.exec() == QDialog::Accepted) {
        QString ip = dialog.ip();
        int port = dialog.port();
        qDebug() << "IP: " << ip << "\nPort: " << port;
    }
}

8.4.5 增加 dialog.h

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>
#include "keypaddialog.h"
#include <QPushButton>
#include <QLineEdit>
#include <QDialogButtonBox>

class Dialog : public QDialog
{
    Q_OBJECT

public:
    Dialog(QWidget *parent = nullptr);
    QString ip();
    int port();

private slots:
    void slotEnterIPAddress();
    void slotEnterPort();

private:
    QPushButton *m_ipButton;
    QLineEdit *m_ipLineEdit;
    QPushButton *m_portButton;
    QLineEdit *m_portLineEdit;
    QDialogButtonBox *m_buttonBox;
    KeypadDialog *m_keypadDialog;
};

#endif // DIALOG_H

8.4.6 增加 dialog.cpp

#include "dialog.h"

Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
{

    setWindowTitle(QString::fromLocal8Bit("设置网络参数对话框"));
    setFixedSize(280, 180);

    m_ipButton = new QPushButton(tr("IP"), this);
    m_ipButton->setFixedSize(80, 30);
    m_ipButton->move(30, 30);

    m_ipLineEdit = new QLineEdit(this);
    m_ipLineEdit->setReadOnly(true);
    m_ipLineEdit->setAlignment(Qt::AlignHCenter);
    m_ipLineEdit->setFixedSize(140, 30);
    m_ipLineEdit->move(130, 30);


    connect(m_ipButton, SIGNAL(clicked()), this, SLOT(slotEnterIPAddress()));

    m_portButton = new QPushButton(tr("Port"), this);
    m_portButton->setFixedSize(80, 30);
    m_portButton->move(30, 70);
    connect(m_portButton, SIGNAL(clicked()), this, SLOT(slotEnterPort()));

    m_portLineEdit = new QLineEdit(this);
    m_portLineEdit->setReadOnly(true);
    m_portLineEdit->setAlignment(Qt::AlignHCenter);
    m_portLineEdit->setFixedSize(140, 30);
    m_portLineEdit->move(130, 70);
#ifdef QT_ARM_PLATFORM
 /*在 Qt4 中,QDialogButtonBox 构造函数需要三个参数,其中第二个参数为布局方式,即横向或纵向排列。由于 Qt5 中已经移除了该参数,
 因此在 Qt4 中需要手动指定。该语句的含义为创建一个包含确定和取消按钮的 QDialogButtonBox 控件,并将其作为子控件添加到当前窗口中。*/

    m_buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, this);

#else
   m_buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
#endif

    m_buttonBox->setFixedSize(180, 40);
    m_buttonBox->move(30, 120);
    connect(m_buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
    connect(m_buttonBox, SIGNAL(rejected()), this, SLOT(reject()));

    m_keypadDialog = new KeypadDialog(this);

}

QString Dialog::ip()
{
    return m_ipLineEdit->text();
}

int Dialog::port()
{
    return m_portLineEdit->text().toInt();
}

void Dialog::slotEnterIPAddress()
{
    m_keypadDialog->setTitle("输入IP地址");
    if (m_keypadDialog->exec() == QDialog::Accepted) {
        m_ipLineEdit->setText(m_keypadDialog->text());
    }
}

void Dialog::slotEnterPort()
{
    m_keypadDialog->setTitle("输入端口号");
    if (m_keypadDialog->exec() == QDialog::Accepted) {
        m_portLineEdit->setText(m_keypadDialog->text());
    }
}

8.4.7 增加 keypaddialog.h

#ifndef KEYPADDIALOG_H
#define KEYPADDIALOG_H

#include <QDialog>
#include <QPushButton>
#include <QLineEdit>

class KeypadDialog : public QDialog
{
    Q_OBJECT

public:
    KeypadDialog(QWidget *parent = nullptr);
    QString text();
    void setTitle(const QString &title);

private slots:
    void slotAddText();
    void slotClearText();

private:
    QPushButton *m_keyButtons[10];
    QPushButton *m_okButton;
    QPushButton *m_cancelButton;
    QPushButton *m_clearButton;
    QLineEdit *m_textLineEdit;
};

#endif // KEYPADDIALOG_H

8.4.8 增加 keypaddialog.cpp

#include "keypaddialog.h"

KeypadDialog::KeypadDialog(QWidget *parent)
    : QDialog(parent)
{
    setWindowTitle(tr("Keypad"));
    setFixedSize(250, 300);

    QStringList strList;
    strList << "1" << "2" << "3" << "4" << "5" << "6" << "7" << "8" << "9" << "0"<<".";

    for (int i = 0; i < 11; i++) {
        m_keyButtons[i] = new QPushButton(strList.at(i), this);
        m_keyButtons[i]->setFixedSize(50, 50);
        m_keyButtons[i]->move((i % 3) * 70 + 20, (i / 3) * 60 + 30);
        m_keyButtons[i]->setFocusPolicy(Qt::NoFocus);
        connect(m_keyButtons[i], SIGNAL(clicked()), this, SLOT(slotAddText()));
    }

    m_clearButton = new QPushButton(tr("Clear"), this);
    m_clearButton->setFixedSize(80, 50);
    m_clearButton->move(20, 240);
    m_clearButton->setFocusPolicy(Qt::NoFocus);
    connect(m_clearButton, SIGNAL(clicked()), this, SLOT(slotClearText()));

    m_okButton = new QPushButton(tr("Ok"), this);
    m_okButton->setFixedSize(80, 50);
    m_okButton->move(150, 240);
    m_okButton->setFocusPolicy(Qt::NoFocus);
    connect(m_okButton, SIGNAL(clicked()), this, SLOT(accept()));

    m_cancelButton = new QPushButton(tr("Cancel"), this);
    m_cancelButton->setFixedSize(80, 50);
    m_cancelButton->move(150, 180);
    m_cancelButton->setFocusPolicy(Qt::NoFocus);
    connect(m_cancelButton, SIGNAL(clicked()), this, SLOT(reject()));

    m_textLineEdit = new QLineEdit(this);
    m_textLineEdit->setReadOnly(true);
    m_textLineEdit->setAlignment(Qt::AlignHCenter);
    m_textLineEdit->setFixedSize(180, 40);
    m_textLineEdit->move(30, 180);

}

QString KeypadDialog::text()
{
    return m_textLineEdit->text();
}

void KeypadDialog::setTitle(const QString &title)
{
    setWindowTitle(title);
}

void KeypadDialog::slotAddText()
{
    QPushButton *button = qobject_cast<QPushButton*>(sender());
    if (!button) {
        return;
    }
    QString str = m_textLineEdit->text().append(button->text());
    m_textLineEdit->setText(str);
}

void KeypadDialog::slotClearText()
{
    m_textLineEdit->setText("");
}

8.5 切换Kit,获得运行在不同系统中的运行的执行文件

点击窗口左边的Debug,可以选择编译运行在不同平台上的可执行文件,arm-v7为arm架构的设备,使用Qt4库,而桌面则是当前ubuntu系统,使用Qt5。(参见8.2节)
Qt5编译完成的可执行程序_qdialogbuttonbox,存放在项目目录的build-_qdialogbuttonbox-unknown-Debug/文件夹下,Qt4编译完成的同名可执行程序_qdialogbuttonbox,存放在项目目录的build-_qdialogbuttonbox-arm_v7-Debug/文件夹下。

8.6 程序中的qt机制

QDialogButtonBox 和 QPushButton 的区别

QDialogButtonBoxQPushButton 都是非常有用的 Qt 组件,具有不同的用途和优点。选择使用哪个类取决于具体的应用场景和设计需求。

  1. 用途不同:
    QPushButton 通常用于窗口或其他界面部件中的单独按钮。而 QDialogButtonBox 通常用于对话框和窗口相关操作的按钮集合。
  2. 风格不同:
    QDialogButtonBox 具有默认外观,并且在应用程序使用主题和样式表时,始终保持相同的一致外观。而 QPushButton 在不同平台和主题中可能会有不同的外观。
  3. 按钮类型:
    QDialogButtonBox 可以包含多个按钮,如“确定”、“取消”、“应用”、“重置”,并且对这些按钮可以进行分组。而 QPushButton 只是一个普通的按钮类。
  4. 信号槽机制:
    QDialogButtonBox 具有许多内置的信号,可以轻松连接到应用程序中的其他部件。与此不同的是,QPushButton 仅为单独的按钮定义了少量的内置信号。

总结

本文介绍QDialogButtonBox按钮编程。通过这个例子,巩固QT的信号与槽知识,了解Qt5对Qt4所做的改进。由于我们的开发的软件显示和输入需要在触摸屏上进行,因此本例演示了如何弹出一个小键盘。
本例程设计是在chatgpt的帮助下完成的,编译代码经过测试通过。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Qt中的setViewport方法可以用于设置QAbstractScrollArea和QGraphicsView的视口大小和位置。它通常与setWidget或setScene方法一起使用以创建可滚动视图。 如果你想要使用setViewport实现缩放,你需要考虑以下几点: 1. 首先,你需要确定视口的大小和位置。 2. 然后,你需要确定如何缩放视口中的内容。你可以使用QTransform类的scale方法来缩放内容。 3. 最后,你需要将缩放后的内容设置为视口的widget或scene。 下面是一个使用setViewport实现缩放的示例代码片段: ``` QGraphicsView *view = new QGraphicsView(this); view->setViewportUpdateMode(QGraphicsView::FullViewportUpdate); view->setRenderHint(QPainter::Antialiasing); view->setDragMode(QGraphicsView::ScrollHandDrag); view->setOptimizationFlag(QGraphicsView::DontAdjustForAntialiasing); view->setInteractive(true); view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); QGraphicsScene *scene = new QGraphicsScene(view); view->setScene(scene); QPixmap pixmap(":/images/image.png"); QGraphicsPixmapItem *item = new QGraphicsPixmapItem(pixmap); scene->addItem(item); QTransform transform; transform.scale(2, 2); item->setTransform(transform); view->setSceneRect(item->boundingRect()); ``` 在这个例子中,我们使用QGraphicsView创建了一个视口,并为其设置了一些属性。然后,我们创建了一个QGraphicsScene,并将其设置为视口的scene。接下来,我们创建了一个QGraphicsPixmapItem,并将其添加到场景中。最后,我们使用QTransform类的scale方法将QGraphicsPixmapItem缩放了两倍,并将其设置为场景的边界矩形。 请注意,这只是一个简单的示例,实际上实现缩放可能需要更多的代码。同时,缩放可能会使内容变得模糊或失真,因此你需要找到一个合适的缩放比例来平衡视觉效果和性能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值