首页 - 新闻 - 编写Qt Designer自定义控件

编写Qt Designer自定义控件

2023-09-30 22:25
-->

1) 流程概览

在使用Qt Designer设计表单界面时,我们可以非常方便地使用Widget Box中的表单控件来绘制界面,比如拖入按钮、文本编辑器等。虽然Qt Designer中的控件可以满足了我们大部分的需求,有时候还有一些特殊的需求,比如输入框。我们要输入的是纬度和经度。此时有两种输入法。它是十进制形式,一种是度、分、秒的形式。这时候仅仅使用简单的LineEdit已经不能满足需求了。我们设想构建这样一个输入控件,它可以支持浮点输入,而且它还有一个属性。改变该属性可以将其切换为经纬度输入形式。如果我们需要在多个表单上输入经纬度,构造这样的控件会非常方便。我们以此为例来说明如何创建自定义表单控件。

第 1 步:创建 QtDesigner 自定义控件项目

打开Qt Creator,创建Qt Designer自定义控件,如下图:

根据向导提示创建项目。这里它被命名为LogLatEdit。项目目录如下图:

步骤2:编译控制工程

为了简化整个自定义控件的编写过程,我们不做任何改动,切换到Release版本,直接编译。

                    步骤 3:部署插件

编译完成后,将生成的dll文件和lib文件一起复制到输出目录中的Qt插件目录中。以我使用的Qt 4.8.4为例,在Qt 4.8.4安装目录D:\Qt\4.8.4下,找到plugins目录,在里面找到designer目录,然后放入dll和lib在里面。完整路径为:D:\Qt\4.8.4\plugins\designer。之后,启动D:\Qt\4.8.4\bin下的designer.exe并创建一个表单。这时你会发现左侧的Widget Box中出现了我们自己的LogLatEdit控件。我们可以像使用其他控件一样,将自己的控件拖到窗体上,如下图:

如果自定义控件没有出现在Widgetbox中,那么你可以通过【帮助-关于插件】菜单打开插件信息对话框,点击刷新按钮,只要你没有忘记复制即可将dll和lib文件放到正确的位置,插件就会自动识别并加载。其他版本的 Qt 也是如此。例如,我自己的计算机上安装了多个版本的 Qt。对于其他版本的Qt,方法是一样的。只需将插件工程生成的dll和lib文件放入对应版本的插件目录即可。就下去吧。

至此,我们已经明确了如何创建自定义控件,并知道了如何部署、加载和使用自定义控件。接下来我们开始编写我们需要的控件。对于只想了解自定义控件开发流程的读者来说,你已经知道怎么做了,所以可以跳过其余内容。

2)控制界面设计

既然是控件,就应该有接口。默认生成的控件类只是继承QWidget的类,如下:

  1. #ifndef LOGLATEDIT_H
  2. #define LOGLATEDIT_H
  3. #包括
  4. 类LogLatEdit:公共QWidget
  5. {
  6. Q_OBJECT
  7. 公众:
  8. LogLatEdit(QWidget *parent = 0);
  9. };
  10. #endif

我们需要的是以下控制组合:

为了简单起见,我不想自己手动去写这些接口相关的代码。为此,我们可以先删除默认生成的loglatedit.h和loglatedit.cpp文件,这样我们就可以重新使用LogLatEdit这个名字来创建一个新的。用户界面类别。右键工程,选择“添加新文件”,使用Qt下的“Qt Designer Interface Class”模板创建ui类,如下图:

对于这个界面类,我们将其重命名为我们需要的控件名称LogLatEdit,然后编辑ui文件,调整QWidget的大小,然后绘制控件,如图:

Horizo​​ntalLayout 控件用于对控件组合进行分组。为了演示方便,这里将两者拖放到一起。最终的控件实际上是两个水平布局相互叠加。一次只能看到一种控制组合。 。

当然,另一种做法也是可行的,即不删除原来默认生成的loglatedit文件,而是将新的ui类命名为其他名称,例如test。绘制完控件后,编译一下,找到Moc生成的ui_test.h文件,打开该文件,我们将相应的代码复制到我们的LogLatEdit控件类中,然后进行适当的修改,比如设置两个控件组合的位置和可见性,为了将所有相关代码放在一起方便读者测试,这里使用了这种方法。

使用ui类更方便。所有界面相关的处理都可以在表单设计器中完成,界面与代码分离。这种代码管理模式逻辑清晰,易于管理。但是,在使用ui类时,如果我们的ui类名不是默认的LogLatEdit,则需要修改插件类中创建插件的代码,主要是修改createWidget方法中返回的控件对象loglateditplugin.cpp 文件。

修改后我们的经纬度控件的代码如下:

  1. #ifndef LOGLATEDIT_H
  2. #define LOGLATEDIT_H
  3. #包括
  4. #包括
  5. #包括
  6. #包括
  7. #包括
  8. #包括
  9. #包括
  10. #包括
  11. #包括
  12. #包括
  13. #包括
  14. #包括
  15. #包括
  16. 类LogLatEdit:公共QWidget
  17. {
  18. Q_OBJECT
  19. 公众:
  20. LogLatEdit(QWidget *parent = 0);
  21. 私人:
  22. QWidget *horizo​​ntalLayoutWidget;
  23. QHBoxLayout *horizo​​ntalLayout;
  24. QSpinBox *spinBox;
  25. QLabel *label_7;
  26. QSpinBox *spinBox_2;
  27. QLabel *label_8;
  28. QDoubleSpinBox *doubleSpinBox;
  29. QLabel *label_9;
  30. QWidget *horizo​​ntalLayoutWidget_2;
  31. QHBoxLayout *horizo​​ntalLayout_2;
  32. QLineEdit *lineEdit;
  33. QLabel *label_6;
  34. QSpacerItem *horizo​​ntalSpacer;
  35. QSpacerItem *horizo​​ntalSpacer_2;
  36. };
  37. #endif

源文件:

  1. #include“loglatedit.h”
  2. LogLatEdit::LogLatEdit(QWidget *parent) :
  3. QWidget(父)
  4. {
  5. 此->调整大小(160, 22);
  6. this->setMinimumSize(QSize(160,22)); //限定控件的大小
  7. this->setMaximumSize(QSize(200,22));
  8. horizo​​ntalLayoutWidget = new QWidget(this);
  9. horizo​​ntalLayoutWidget->setObjectName(QString::fromUtf8("horizo​​ntalLayoutWidget"));
  10. horizo​​ntalLayoutWidget->setGeometry(QRect(0, 0, 160, 22));
  11. horizo​​ntalLayout = new QHBoxLayout(horizo​​ntalLayoutWidget);
  12. horizo​​ntalLayout->setSpacing(1);
  13. horizo​​ntalLayout->setObjectName(QString::fromUtf8("horizo​​ntalLayout"));
  14. horizo​​ntalLayout->setContentsMargins(0, 0, 0, 0);
  15. spinBox = new QSpinBox(horizo​​ntalLayoutWidget);
  16. spinBox->setObjectName(QString::fromUtf8("spinBox"));
  17. spinBox->setMinimumSize(QSize(35, 20));
  18. spinBox->setMaximumSize(QSize(35, 20));
  19. spinBox->setMaximum(90);
  20. horizo​​ntalLayout->addWidget(spinBox);
  21. label_7 = 新QLabel(horizo​​ntalLayoutWidget);
  22. label_7->setObjectName(QString::fromUtf8("label_7"));
  23. QSizePolicy sizePolicy(QSizePolicy::固定,QSizePolicy::首选);
  24. sizePolicy.setHorizo​​ntalStretch(0);
  25. sizePolicy.setVerticalStretch(0);
  26. sizePolicy.setHeightForWidth(label_7->sizePolicy().hasHeightForWidth());
  27. label_7->setSizePolicy(sizePolicy);
  28. label_7->setMinimumSize(QSize(3, 20));
  29. label_7->setSizeIncrement(QSize(1, 0));
  30. horizo​​ntalLayout->addWidget(label_7);
  31. horizo​​ntalSpacer = 新 QSpacerItem(0, 20, QSizePolicy::扩展, QSizePolicy::最小值);
  32. horizo​​ntalLayout->addItem(horizo​​ntalSpacer);
  33. spinBox_2 = new QSpinBox(horizo​​ntalLayoutWidget);
  34. spinBox_2->setObjectName(QString::fromUtf8("spinBox_2"));
  35. spinBox_2->setMinimumSize(QSize(35, 20));
  36. spinBox_2->setMaximumSize(QSize(35, 20));
  37. spinBox_2->setMaximum(90);
  38. horizo​​ntalLayout->addWidget(spinBox_2);
  39. label_8 = new QLabel(horizo​​ntalLayoutWidget);
  40. label_8->setObjectName(QString::fromUtf8("label_8"));
  41. sizePolicy.setHeightForWidth(label_8->sizePolicy().hasHeightForWidth());
  42. label_8->setSizePolicy(sizePolicy);
  43. label_8->setMinimumSize(QSize(3, 20));
  44. label_8->setSizeIncrement(QSize(1, 0));
  45. horizo​​ntalLayout->addWidget(label_8);
  46. horizo​​ntalSpacer_2 = new QSpacerItem(0, 20, QSizePolicy::扩展, QSizePolicy::最小值);
  47. horizo​​ntalLayout->addItem(horizo​​ntalSpacer_2);
  48. doubleSpinBox = new QDoubleSpinBox(horizo​​ntalLayoutWidget);
  49. doubleSpinBox->setObjectName(QString::fromUtf8("doubleSpinBox"));
  50. doubleSpinBox->setMinimumSize(QSize(66, 20));
  51. doubleSpinBox->setMaximumSize(QSize(66, 20));
  52. doubleSpinBox->setDecimals(4);
  53. doubleSpinBox->setMaximum(90);
  54. horizo​​ntalLayout->addWidget(doubleSpinBox);
  55. label_9 = new QLabel(horizo​​ntalLayoutWidget);
  56. label_9->setObjectName(QString::fromUtf8("label_9"));
  57. sizePolicy.setHeightForWidth(label_9->sizePolicy().hasHeightForWidth());
  58. label_9->setSizePolicy(sizePolicy);
  59. label_9->setMinimumSize(QSize(3, 20));
  60. label_9->setSizeIncrement(QSize(1, 0));
  61. horizo​​ntalLayout->addWidget(label_9);
  62. horizo​​ntalLayoutWidget_2 = 新 QWidget(this);
  63. horizo​​ntalLayoutWidget_2->setObjectName(QString::fromUtf8("horizo​​ntalLayoutWidget_2"));
  64. horizo​​ntalLayoutWidget_2->setGeometry(QRect(0, 0, 160, 22));
  65. horizo​​ntalLayout_2 = new QHBoxLayout(horizo​​ntalLayoutWidget_2);
  66. horizo​​ntalLayout_2->setSpacing(1);
  67. horizo​​ntalLayout_2->setObjectName(QString::fromUtf8("horizo​​ntalLayout_2"));
  68. horizo​​ntalLayout_2->setContentsMargins(0, 0, 0, 0);
  69. lineEdit = new QLineEdit(horizo​​ntalLayoutWidget_2);
  70. lineEdit->setObjectName(QString::fromUtf8("lineEdit"));
  71. lineEdit->setInputMethodHints(Qt::ImhDigitsOnly|Qt::ImhFormattedNumbersOnly);
  72. horizo​​ntalLayout_2->addWidget(lineEdit);
  73. label_6 = 新QLabel(horizo​​ntalLayoutWidget_2);
  74. label_6->setObjectName(QString::fromUtf8("label_6"));
  75. horizo​​ntalLayout_2->addWidget(label_6);
  76. label_7->setText(QApplication::translate("LogLatEdit", "\302\260", 0, QApplication::UnicodeUTF8));
  77. label_8->setText(QApplication::translate("LogLatEdit", "\342\200\262", 0, QApplication::UnicodeUTF8));
  78. label_9->setText(QApplication::translate("LogLatEdit", "\342\200\263", 0, QApplication::UnicodeUTF8));
  79. label_6->setText(QApplication::translate("LogLatEdit", "\302\260", 0, QApplication::UnicodeUTF8));
  80. horizo​​ntalLayoutWidget_2->setVisible(false);
  81. QMetaObject::connectSlotsByName(this);
  82. }

至此,界面相关的事情就完成了。稍后我们需要给这个控件添加两个属性,一个是输入模式属性。当改变这个属性时,我们的控件可以在两种输入模式之间切换。另一个属性是纬度和经度值,我们希望能够设置和返回纬度和经度值。

3)控制属性功能实现

表单控件有属性,如QLineEdit的text属性,也有设置属性,如QLineEdit的readOnly属性。让我们解释一下如何向您自己的控件添加属性。对于我们的经度和纬度输入控件,它应该有一个设置属性和一个值属性。我们将设置属性命名为 inputMode 并将 value 属性命名为 value。我们先解释一下设置属性inputMode。

对于inputMode属性来说,应该是一个枚举值,对应控件的两种状态,即浮点输入模式和经纬度输入模式,所以该类型应该定义为枚举类型。另外,对于Qt的控件类,如何声明属性,我们可以参考Qt的源码,比如D:\Qt\4.8.4\src\gui\widgets目录下QMainWindow的定义。我们可以按照它的方法来实现输入模式属性。 ,这里就不多解释了,直接给出代码:

  1. LogLatEdit 类:公共 QWidget
  2. {
  3. Q_OBJECT
  4. Q_ENUMS(输入模式)
  5. Q_PROPERTY(InputMode inputMode READ inputMode WRITE setInputMode)
  6. Q_PROPERTY(浮点值读取值写入设置值)
  7. 公众:
  8. LogLatEdit(QWidget *parent = 0);
  9. 枚举输入模式
  10. {
  11. Float, //浮点数模式
  12. DegSecMin //度秒分模式
  13. };
  14. 输入模式 inputMode()const;
  15. void setInputMode(const InputMode mode);
  16. double value() const;
  17. void setValue(const double val);
  18. //其余省略
  19. };

以 QMainWindow 的 DockOptions 属性和 iconSize 属性为模型,我们实现了 inputMode 和 value 属性。这里要注意使用Q_PROPERTY宏声明属性的方法。使用方法非常简单,无需解释。以下是对应属性的实现代码:

  1. LogLatEdit::InputMode LogLatEdit::inputMode() const
  2. {
  3. 返回m_Mode;
  4. }
  5. void LogLatEdit::setInputMode(const InputMode 模式)
  6. {
  7. double val = this->value();
  8. if(模式==DegSecMin)
  9. {
  10. horizo​​ntalLayoutWidget->setVisible(true);
  11. horizo​​ntalLayoutWidget_2->setVisible(false);
  12. }
  13. 其他
  14. {
  15. horizo​​ntalLayoutWidget->setVisible(false);
  16. horizo​​ntalLayoutWidget_2->setVisible(true);
  17. }
  18. m_Mode = 模式;
  19. this->setValue(val);
  20. }
  21. double LogLatEdit::value() const
  22. {
  23. if(this->inputMode()==Float)
  24. {
  25. 返回此->lineEdit->text().toDouble();
  26. }
  27. 其他
  28. {
  29. 双值=0;
  30. val = this->spinBox->value() +
  31. double(this->spinBox_2->value())/60.0 +
  32. this->doubleSpinBox->value()/3600.0;
  33. 返回值;
  34. }
  35. }
  36. void LogLatEdit::setValue(const double val)
  37. {
  38. m_Value = val;
  39. if(this->inputMode()==Float)
  40. {
  41. this->lineEdit->setText(tr("%1").arg(val));
  42. }
  43. 其他
  44. {
  45. this->spinBox->setValue(int(val));
  46. this->spinBox_2->setValue(int((val-int(val))*60));
  47. this->doubleSpinBox->setValue(((val-int(val))*60-int((val-int(val))*60)));
  48. }
  49. }

控件编写完毕以后,把生成的dll和lib文件一起复制到Qt安装目录下的插件目录里,比如我安装在D盘里的Qt 4.8.4,路径为:D:\Qt\4.8。 4\plugins\designer,复制进去以后,这个插件就可以被Qt Designer加载了,此时这个自定义控件就可以像普通的控件一样使用了。当然如果需要,还可以给这个控件添加一些信号和槽,另外按照经纬度的取值范围不同,做一下区分经度和维度的处理,本例中不需要这么复杂,就不再深入探索了,下面是使用自定义的经纬度输入控件的效果:

当我将自定义控件的dll和lib文件复制到D:\Qt\4.8.4\plugins\designer目录下,然后启动D:\Qt\4.8.4\bin中的designer.exe目录下,这个插件可以加载到Widget Box中,但是如果我在D:\Qt\qtcreator-2.8.1\bin目录下启动Qt Creator,我们的插件就不会出现在Qt Creator设计器中。因此,对于Qt Creator,我们还需要安装以下控件,那么它们应该安装在哪里呢?在Qt Creator安装目录中查找后发现在目录D:\Qt\qtcreator-2.8.1\bin下有一个与D:\Qt\4.8.4\plugins\designer目录同名的dll \插件\设计器。文件,所以我们猜测该目录是Qt Creator的控件安装目录。接下来我们将loglateditplugin.dll复制到该目录下,然后重新打开Qt Creator,发现自定义控件加载成功,这样第一个问题就解决了。

通过以上实验,我们可以总结出具体方法如下:

1。创建Qt Designer自定义控件项目并编写自定义控件;

2。将release版本的dll和lib文件复制到Qt Designer的插件目录下,如D:\Qt\4.8.4\plugins\designer,这样就可以在Qt Designer中使用自定义控件了;

3。将dll文件复制到Qt Creator集成Qt Designer的插件目录下,如:D:\Qt\qtcreator-2.8.1\bin\plugins\designer,这样Qt Creator中集成的Qt Designer就可以加载并使用使用控件;

4。将自定义控件的头文件和源文件复制到使用自定义控件的工程中,并添加到工程中,这样就可以正确编译和连接。

-->