【QT用户登录与界面跳转】

news2025/1/19 13:28:48

【QT用户登录与界面跳转】

  • 1.前言
  • 2. 项目设置
  • 3.设计登录界面
    • 3.1 login.pro参数
    • 3.2 界面设置
      • 3.2.1 登录界面
      • 3.2.2 串口主界面
  • 4. 实现登录逻辑
  • 5.串口界面
  • 6.测试功能
  • 7.总结

1.前言

在Qt应用程序开发中,实现用户登录及界面跳转功能是构建交互式应用的重要步骤之一。下面将介绍如何使用Qt框架来创建一个简单的用户登录界面,并根据用户的输入信息进行验证,然后跳转到相应的【QT串口助手】主界面。
源码地址:

2. 项目设置

首先,确保你的开发环境中已安装了Qt及其相关工具(如Qt Creator),前期也安装过QT(参考博客:【Qt安装与简易串口控制Arduino开发板小灯教程】)。本文记录一下用QT Creator 写一个用户登录与界面串口助手的过程,整个工程只有几百行代码,跟着做下来对新手来说可以更快了解整个QT项目的开发过程和一些常用控件的使用方法。最好每个功能自己都试试增加自信心!
💕💕💕
先来看看作品:
在这里插入图片描述

3.设计登录界面

3.1 login.pro参数

  1. 设置login.pro参数,导入core gui serialport库
 QT       += core gui serialport

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 += \
    main.cpp \
    mainwindow.cpp \
    serial.cpp

HEADERS += \
    mainwindow.h \
    serial.h

FORMS += \
    mainwindow.ui \
    serial.ui

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

RESOURCES += \
    source.qrc

3.2 界面设置

界面设置分为登录界面和串口主界面

3.2.1 登录界面

在这里插入图片描述
这个登录界面是为智能船舶自主航行系统设计的,提供了简洁而功能齐全的用户登录体验。界面顶部展示有系统名称,明确了这是进入系统的入口。用户需要输入账号和密码来验证身份,其中密码输入框支持显示或隐藏密码的功能以增强使用便捷性。此外,提供了一个“记住账号密码”的选项,方便用户的下次登录。整个背景采用了半透明处理的船舶图像,既美化了界面也强化了品牌形象,使得登录过程更加直观友好。底部还设有一个“忘记密码”链接,为用户提供了找回密码的途径。整体设计注重用户体验,确保了安全性和易用性的平衡。
mainwindow.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>501</width>
    <height>403</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <widget class="QFrame" name="frame">
    <property name="geometry">
     <rect>
      <x>30</x>
      <y>20</y>
      <width>431</width>
      <height>351</height>
     </rect>
    </property>
    <property name="frameShape">
     <enum>QFrame::StyledPanel</enum>
    </property>
    <property name="frameShadow">
     <enum>QFrame::Raised</enum>
    </property>
    <widget class="QGroupBox" name="groupBox">
     <property name="geometry">
      <rect>
       <x>20</x>
       <y>20</y>
       <width>391</width>
       <height>311</height>
      </rect>
     </property>
     <property name="font">
      <font>
       <pointsize>14</pointsize>
      </font>
     </property>
     <property name="title">
      <string>智能船舶自主航行系统软件登录</string>
     </property>
     <widget class="QPushButton" name="pushButton">
      <property name="geometry">
       <rect>
        <x>100</x>
        <y>260</y>
        <width>161</width>
        <height>41</height>
       </rect>
      </property>
      <property name="font">
       <font>
        <pointsize>20</pointsize>
       </font>
      </property>
      <property name="text">
       <string>登录</string>
      </property>
     </widget>
     <widget class="QCheckBox" name="checkBox">
      <property name="geometry">
       <rect>
        <x>80</x>
        <y>230</y>
        <width>121</width>
        <height>21</height>
       </rect>
      </property>
      <property name="font">
       <font>
        <pointsize>11</pointsize>
       </font>
      </property>
      <property name="text">
       <string>记住账号密码</string>
      </property>
     </widget>
     <widget class="QCommandLinkButton" name="commandLinkButton">
      <property name="geometry">
       <rect>
        <x>220</x>
        <y>220</y>
        <width>101</width>
        <height>41</height>
       </rect>
      </property>
      <property name="font">
       <font>
        <family>Segoe UI</family>
        <pointsize>11</pointsize>
       </font>
      </property>
      <property name="text">
       <string>忘记密码</string>
      </property>
     </widget>
     <widget class="QLineEdit" name="accout">
      <property name="geometry">
       <rect>
        <x>100</x>
        <y>90</y>
        <width>201</width>
        <height>31</height>
       </rect>
      </property>
     </widget>
     <widget class="QLineEdit" name="password">
      <property name="geometry">
       <rect>
        <x>100</x>
        <y>150</y>
        <width>201</width>
        <height>31</height>
       </rect>
      </property>
     </widget>
     <widget class="QLabel" name="label">
      <property name="geometry">
       <rect>
        <x>40</x>
        <y>90</y>
        <width>71</width>
        <height>31</height>
       </rect>
      </property>
      <property name="font">
       <font>
        <family>华文中宋</family>
        <pointsize>14</pointsize>
       </font>
      </property>
      <property name="text">
       <string>账号:</string>
      </property>
     </widget>
     <widget class="QLabel" name="label_2">
      <property name="geometry">
       <rect>
        <x>40</x>
        <y>150</y>
        <width>71</width>
        <height>31</height>
       </rect>
      </property>
      <property name="font">
       <font>
        <family>华文中宋</family>
        <pointsize>14</pointsize>
       </font>
      </property>
      <property name="text">
       <string>密码:</string>
      </property>
     </widget>
     <widget class="QRadioButton" name="radioButton">
      <property name="geometry">
       <rect>
        <x>310</x>
        <y>155</y>
        <width>81</width>
        <height>21</height>
       </rect>
      </property>
      <property name="text">
       <string>显示</string>
      </property>
     </widget>
    </widget>
   </widget>
  </widget>
 </widget>
 <resources/>
 <connections/>
</ui>

3.2.2 串口主界面

在这里插入图片描述
该串口工具界面设计用于简化与串行设备的通信过程,设计过程参考【QT串口助手】,提供直观的操作体验。界面主要分为几个关键部分:

  • 串口配置区域:用户可以在此选择和配置串口参数,包括端口号、波特率、数据位、校验位以及停止位,以确保与目标设备正确匹配。
  • 操作控制按钮:包含检测串口、打开/关闭串口等按钮,便于用户快速操作串口连接状态。
  • 接收设置选项:允许用户根据需求调整接收数据的方式,如启用Hex显示模式、添加时间戳以及自动换行功能,方便查看接收到的数据。
  • 发送设置选项:提供Hex发送模式及发送后自动换行的功能,同时支持设定自动发送间隔时间,适合需要周期性发送数据的应用场景。
  • 数据交互区:分为发送数据区和接收数据显示区,前者让用户输入要发送到串口的数据,后者实时展示从串口接收到的信息,两者均配备了清空内容的快捷按钮,提升用户体验。

整体而言,此串口界面旨在为用户提供一个高效且易于使用的平台,以便于进行串口通信调试和管理,满足不同应用场景下的串口操作需求。
serial.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>Serial</class>
 <widget class="QMainWindow" name="Serial">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>578</width>
    <height>527</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <widget class="QGroupBox" name="groupBox_4">
    <property name="geometry">
     <rect>
      <x>200</x>
      <y>10</y>
      <width>351</width>
      <height>481</height>
     </rect>
    </property>
    <property name="title">
     <string>数据交互</string>
    </property>
    <widget class="QWidget" name="formLayoutWidget">
     <property name="geometry">
      <rect>
       <x>0</x>
       <y>20</y>
       <width>341</width>
       <height>451</height>
      </rect>
     </property>
     <layout class="QFormLayout" name="formLayout">
      <item row="0" column="0">
       <widget class="QLabel" name="label_2">
        <property name="text">
         <string>发送数据</string>
        </property>
       </widget>
      </item>
      <item row="1" column="0" colspan="2">
       <widget class="QTextEdit" name="textEdit_send"/>
      </item>
      <item row="2" column="0">
       <widget class="QLabel" name="label">
        <property name="text">
         <string>接收数据</string>
        </property>
       </widget>
      </item>
      <item row="3" column="0" colspan="2">
       <widget class="QTextEdit" name="textEdit_recv">
        <property name="readOnly">
         <bool>true</bool>
        </property>
       </widget>
      </item>
      <item row="4" column="0" colspan="2">
       <layout class="QHBoxLayout" name="horizontalLayout_2">
        <item>
         <spacer name="horizontalSpacer">
          <property name="orientation">
           <enum>Qt::Horizontal</enum>
          </property>
          <property name="sizeHint" stdset="0">
           <size>
            <width>40</width>
            <height>20</height>
           </size>
          </property>
         </spacer>
        </item>
        <item>
         <widget class="QPushButton" name="send_Bt">
          <property name="text">
           <string>发送数据</string>
          </property>
         </widget>
        </item>
        <item>
         <spacer name="horizontalSpacer_2">
          <property name="orientation">
           <enum>Qt::Horizontal</enum>
          </property>
          <property name="sizeHint" stdset="0">
           <size>
            <width>40</width>
            <height>20</height>
           </size>
          </property>
         </spacer>
        </item>
        <item>
         <widget class="QPushButton" name="clear_send_Bt">
          <property name="text">
           <string>清空发送区</string>
          </property>
         </widget>
        </item>
        <item>
         <spacer name="horizontalSpacer_4">
          <property name="orientation">
           <enum>Qt::Horizontal</enum>
          </property>
          <property name="sizeHint" stdset="0">
           <size>
            <width>40</width>
            <height>20</height>
           </size>
          </property>
         </spacer>
        </item>
       </layout>
      </item>
     </layout>
    </widget>
   </widget>
   <widget class="QGroupBox" name="groupBox">
    <property name="geometry">
     <rect>
      <x>10</x>
      <y>10</y>
      <width>191</width>
      <height>311</height>
     </rect>
    </property>
    <property name="title">
     <string>串口配置</string>
    </property>
    <widget class="QWidget" name="gridLayoutWidget_2">
     <property name="geometry">
      <rect>
       <x>10</x>
       <y>20</y>
       <width>169</width>
       <height>281</height>
      </rect>
     </property>
     <layout class="QGridLayout" name="gridLayout_2">
      <item row="1" column="0">
       <spacer name="verticalSpacer">
        <property name="orientation">
         <enum>Qt::Vertical</enum>
        </property>
        <property name="sizeHint" stdset="0">
         <size>
          <width>20</width>
          <height>40</height>
         </size>
        </property>
       </spacer>
      </item>
      <item row="2" column="0">
       <widget class="QPushButton" name="Serial_check_Bt">
        <property name="minimumSize">
         <size>
          <width>93</width>
          <height>28</height>
         </size>
        </property>
        <property name="text">
         <string>检测串口</string>
        </property>
       </widget>
      </item>
      <item row="3" column="0">
       <widget class="QPushButton" name="open_serial_Bt">
        <property name="minimumSize">
         <size>
          <width>93</width>
          <height>28</height>
         </size>
        </property>
        <property name="text">
         <string>打开串口</string>
        </property>
       </widget>
      </item>
      <item row="0" column="0">
       <layout class="QGridLayout" name="gridLayout" rowstretch="0,0,0,0,0,0" columnstretch="0,0">
        <property name="sizeConstraint">
         <enum>QLayout::SetDefaultConstraint</enum>
        </property>
        <property name="leftMargin">
         <number>0</number>
        </property>
        <property name="topMargin">
         <number>0</number>
        </property>
        <property name="rightMargin">
         <number>0</number>
        </property>
        <property name="bottomMargin">
         <number>0</number>
        </property>
        <property name="horizontalSpacing">
         <number>6</number>
        </property>
        <property name="verticalSpacing">
         <number>0</number>
        </property>
        <item row="3" column="0">
         <widget class="QLabel" name="label_databit">
          <property name="minimumSize">
           <size>
            <width>72</width>
            <height>30</height>
           </size>
          </property>
          <property name="maximumSize">
           <size>
            <width>76</width>
            <height>30</height>
           </size>
          </property>
          <property name="text">
           <string>数据位:</string>
          </property>
         </widget>
        </item>
        <item row="4" column="0">
         <widget class="QLabel" name="label_parity">
          <property name="minimumSize">
           <size>
            <width>72</width>
            <height>30</height>
           </size>
          </property>
          <property name="maximumSize">
           <size>
            <width>76</width>
            <height>30</height>
           </size>
          </property>
          <property name="text">
           <string>校验位:</string>
          </property>
         </widget>
        </item>
        <item row="1" column="1">
         <widget class="QComboBox" name="serial_Cb">
          <property name="minimumSize">
           <size>
            <width>87</width>
            <height>22</height>
           </size>
          </property>
          <property name="maximumSize">
           <size>
            <width>76</width>
            <height>15</height>
           </size>
          </property>
         </widget>
        </item>
        <item row="5" column="0">
         <widget class="QLabel" name="label_stopbit">
          <property name="minimumSize">
           <size>
            <width>72</width>
            <height>30</height>
           </size>
          </property>
          <property name="maximumSize">
           <size>
            <width>76</width>
            <height>30</height>
           </size>
          </property>
          <property name="text">
           <string>停止位:</string>
          </property>
         </widget>
        </item>
        <item row="5" column="1">
         <widget class="QComboBox" name="stopbit_Cb">
          <property name="minimumSize">
           <size>
            <width>87</width>
            <height>22</height>
           </size>
          </property>
          <property name="maximumSize">
           <size>
            <width>76</width>
            <height>15</height>
           </size>
          </property>
          <item>
           <property name="text">
            <string>none</string>
           </property>
          </item>
          <item>
           <property name="text">
            <string>奇校验</string>
           </property>
          </item>
          <item>
           <property name="text">
            <string>偶校验</string>
           </property>
          </item>
         </widget>
        </item>
        <item row="4" column="1">
         <widget class="QComboBox" name="checkbit_Cb">
          <property name="minimumSize">
           <size>
            <width>87</width>
            <height>22</height>
           </size>
          </property>
          <property name="maximumSize">
           <size>
            <width>76</width>
            <height>15</height>
           </size>
          </property>
          <item>
           <property name="text">
            <string>1</string>
           </property>
          </item>
          <item>
           <property name="text">
            <string>1.5</string>
           </property>
          </item>
          <item>
           <property name="text">
            <string>2</string>
           </property>
          </item>
         </widget>
        </item>
        <item row="2" column="1">
         <widget class="QComboBox" name="baundrate_Cb">
          <property name="minimumSize">
           <size>
            <width>87</width>
            <height>22</height>
           </size>
          </property>
          <property name="maximumSize">
           <size>
            <width>76</width>
            <height>15</height>
           </size>
          </property>
          <property name="currentText">
           <string>9600</string>
          </property>
          <property name="currentIndex">
           <number>3</number>
          </property>
          <item>
           <property name="text">
            <string>1200</string>
           </property>
          </item>
          <item>
           <property name="text">
            <string>2400</string>
           </property>
          </item>
          <item>
           <property name="text">
            <string>4800</string>
           </property>
          </item>
          <item>
           <property name="text">
            <string>9600</string>
           </property>
          </item>
          <item>
           <property name="text">
            <string>19200</string>
           </property>
          </item>
          <item>
           <property name="text">
            <string>38400</string>
           </property>
          </item>
          <item>
           <property name="text">
            <string>57600</string>
           </property>
          </item>
          <item>
           <property name="text">
            <string>115200</string>
           </property>
          </item>
         </widget>
        </item>
        <item row="1" column="0">
         <widget class="QLabel" name="label_serialport">
          <property name="minimumSize">
           <size>
            <width>72</width>
            <height>30</height>
           </size>
          </property>
          <property name="maximumSize">
           <size>
            <width>76</width>
            <height>30</height>
           </size>
          </property>
          <property name="text">
           <string>端口号:</string>
          </property>
         </widget>
        </item>
        <item row="2" column="0">
         <widget class="QLabel" name="label_baudrate">
          <property name="minimumSize">
           <size>
            <width>72</width>
            <height>30</height>
           </size>
          </property>
          <property name="maximumSize">
           <size>
            <width>76</width>
            <height>30</height>
           </size>
          </property>
          <property name="text">
           <string>波特率:</string>
          </property>
         </widget>
        </item>
        <item row="3" column="1">
         <widget class="QComboBox" name="databit_Cb">
          <property name="minimumSize">
           <size>
            <width>87</width>
            <height>22</height>
           </size>
          </property>
          <property name="maximumSize">
           <size>
            <width>76</width>
            <height>15</height>
           </size>
          </property>
          <property name="currentText">
           <string>8</string>
          </property>
          <item>
           <property name="text">
            <string>8</string>
           </property>
          </item>
          <item>
           <property name="text">
            <string>7</string>
           </property>
          </item>
          <item>
           <property name="text">
            <string>6</string>
           </property>
          </item>
          <item>
           <property name="text">
            <string>5</string>
           </property>
          </item>
         </widget>
        </item>
       </layout>
      </item>
     </layout>
    </widget>
   </widget>
   <widget class="QGroupBox" name="groupBox_2">
    <property name="geometry">
     <rect>
      <x>10</x>
      <y>330</y>
      <width>191</width>
      <height>81</height>
     </rect>
    </property>
    <property name="title">
     <string>接收设置</string>
    </property>
    <widget class="QWidget" name="formLayoutWidget_2">
     <property name="geometry">
      <rect>
       <x>10</x>
       <y>20</y>
       <width>189</width>
       <height>56</height>
      </rect>
     </property>
     <layout class="QFormLayout" name="formLayout_2">
      <item row="0" column="0">
       <widget class="QPushButton" name="clear_recv_Bt">
        <property name="text">
         <string>清空接收</string>
        </property>
       </widget>
      </item>
      <item row="0" column="1">
       <widget class="QCheckBox" name="recv_hex_Chb">
        <property name="text">
         <string>Hex接收</string>
        </property>
       </widget>
      </item>
      <item row="1" column="0">
       <widget class="QCheckBox" name="recv_time_Chb">
        <property name="text">
         <string>时间戳</string>
        </property>
       </widget>
      </item>
      <item row="1" column="1">
       <widget class="QCheckBox" name="recv_autoline_Chb">
        <property name="text">
         <string>自动换行</string>
        </property>
       </widget>
      </item>
     </layout>
    </widget>
   </widget>
   <widget class="QGroupBox" name="groupBox_3">
    <property name="geometry">
     <rect>
      <x>10</x>
      <y>420</y>
      <width>191</width>
      <height>71</height>
     </rect>
    </property>
    <property name="title">
     <string>发送设置</string>
    </property>
    <widget class="QWidget" name="layoutWidget">
     <property name="geometry">
      <rect>
       <x>10</x>
       <y>20</y>
       <width>183</width>
       <height>49</height>
      </rect>
     </property>
     <layout class="QGridLayout" name="gridLayout_5">
      <item row="0" column="0">
       <widget class="QCheckBox" name="send_hex_Chb">
        <property name="text">
         <string>Hex发送</string>
        </property>
       </widget>
      </item>
      <item row="0" column="1" colspan="2">
       <widget class="QCheckBox" name="send_line_Chb">
        <property name="text">
         <string>发送新行</string>
        </property>
       </widget>
      </item>
      <item row="1" column="0">
       <widget class="QCheckBox" name="autosend_Chb">
        <property name="text">
         <string>自动发送</string>
        </property>
       </widget>
      </item>
      <item row="1" column="1">
       <widget class="QSpinBox" name="txtSendMs">
        <property name="minimumSize">
         <size>
          <width>60</width>
          <height>0</height>
         </size>
        </property>
        <property name="readOnly">
         <bool>false</bool>
        </property>
       </widget>
      </item>
      <item row="1" column="2">
       <widget class="QLabel" name="label_3">
        <property name="text">
         <string>ms</string>
        </property>
       </widget>
      </item>
     </layout>
    </widget>
   </widget>
  </widget>
  <widget class="QStatusBar" name="statusbar"/>
  <widget class="QMenuBar" name="menuBar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>578</width>
     <height>23</height>
    </rect>
   </property>
   <widget class="QMenu" name="menu">
    <property name="title">
     <string>串口工具</string>
    </property>
   </widget>
   <widget class="QMenu" name="menuTCP">
    <property name="title">
     <string>TCP工具</string>
    </property>
   </widget>
   <widget class="QMenu" name="menuUDP">
    <property name="title">
     <string>UDP工具</string>
    </property>
   </widget>
   <widget class="QMenu" name="menuCAN">
    <property name="title">
     <string>CAN工具</string>
    </property>
   </widget>
   <widget class="QMenu" name="menu_2">
    <property name="title">
     <string>画图工具</string>
    </property>
   </widget>
   <addaction name="menu"/>
   <addaction name="menuTCP"/>
   <addaction name="menuUDP"/>
   <addaction name="menuCAN"/>
   <addaction name="menu_2"/>
  </widget>
 </widget>
 <resources/>
 <connections/>
</ui>

4. 实现登录逻辑

main.cpp主程序进入界面

#include "mainwindow.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

在对应的mainwindow.cpp文件中实现登录逻辑:

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "serial.h"
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , settings(new QSettings("YourCompany", "YourApp"))
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    // 设置背景图片
    QFile file(":/ship.png"); // 如果使用资源系统,请根据实际情况调整路径
    if(file.exists()) {
        this->setStyleSheet("MainWindow { background-image: url(:/ship.png)};");
    } else
    {
        qDebug() << "Background image not found!";
    }
    //隐匿密码
    ui->password->setEchoMode(QLineEdit::Password);
    //登录按钮
    connect(ui->pushButton, &QPushButton::clicked, this, &MainWindow::login);
    //按钮传参显示密码按钮
    connect(ui->radioButton, &QPushButton::clicked, this, &MainWindow::display_psd);
    // 记住密码复选框
    connect(ui->checkBox, &QCheckBox::stateChanged, this, &MainWindow::saveSettings);
    loadSettings();
}

MainWindow::~MainWindow()
{
    delete ui;
    delete settings;
}


void MainWindow::login()
{
    saveSettings();
    QString nameString = ui->accout->text();
    QString pswdString = ui->password->text();

    // 检查用户名和密码是否匹配
    if ((nameString == QString::fromLocal8Bit("admin") && pswdString == QString::fromLocal8Bit("123456")) ||
            (nameString == QString::fromLocal8Bit("user") && pswdString == QString::fromLocal8Bit("111111"))) {
        Serial* w = new Serial(); // 使用 'this' 作为父对象,Qt 会自动管理其生命周期
        qDebug() << "Creating Software instance.";
        this->close();
        w->show();
    } else
    {
        QMessageBox::about(this, "警告", "用户名或密码错误");
    }
}

void MainWindow::display_psd(bool checked)
{
    if (checked) {
        //显示密码
        ui->password->setEchoMode(QLineEdit::Normal);
    }
    else {
        //密文显示
        ui->password->setEchoMode(QLineEdit::Password);
    }
}

void MainWindow::saveSettings()
{
    bool remember = ui->checkBox->isChecked();
    QString username = ui->accout->text();
    QString password = ui->password->text();

    settings->setValue("remember", remember);
    if (remember) {
        settings->setValue("username", username);
        settings->setValue("password", password);
    } else {
        settings->remove("username");
        settings->remove("password");
    }
}
void MainWindow::loadSettings()
{
    bool remember = settings->value("remember", false).toBool();
    QString username = settings->value("username", "").toString();
    QString password = settings->value("password", "").toString();

    ui->checkBox->setChecked(remember);
    ui->accout->setText(username);
    ui->password->setText(password);
}

这段代码实现了一个简单的登录窗口,具备记住密码、显示/隐藏密码和基本的用户验证功能。以下是各部分的功能概述:

  1. 构造函数 MainWindow::MainWindow

    • 初始化主窗口,设置背景图片(如果存在),并初始化一些UI元素。
    • 为密码输入框设置密码模式(即隐藏输入字符)。
    • 连接按钮和复选框到相应的槽函数,以便处理用户的交互操作。
    • 调用 loadSettings() 函数加载上次保存的设置。
  2. 析构函数 MainWindow::~MainWindow

    • 清理资源,包括删除UI对象和设置对象。
  3. login 函数

    • 验证用户名和密码是否正确。如果匹配,则关闭当前登录窗口,并打开一个新的 Serial 窗口。
    • 如果不匹配,弹出一个警告消息框提示用户名或密码错误。
  4. display_psd 函数

    • 根据复选框的状态切换密码输入框的显示模式:如果选中则显示密码文本,否则隐藏(以圆点形式显示)。
  5. saveSettingsloadSettings 函数

    • saveSettings:根据复选框状态决定是否保存用户名和密码。如果用户选择了“记住密码”,则将这些信息保存到应用设置中;否则,从设置中移除这些信息。
    • loadSettings:在启动时读取保存的设置,并根据这些设置更新UI组件(例如,自动填写用户名和密码,以及勾选“记住密码”复选框)。

整体来说,这段代码主要实现了以下功能:

  • 提供了一个图形界面用于用户登录。
  • 支持记住用户凭据的功能,方便用户下次登录。
  • 提供了显示/隐藏密码选项,增加了用户体验。
  • 在验证用户身份后,可以跳转到另一个应用界面(Serial 窗口)。

请注意,直接存储密码的做法存在安全风险,在实际应用中应采用更安全的方式处理用户认证信息。
mainwindow.h预定义槽函数,导入QT相关的库

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QMessageBox>
#include <QSettings>
#include <QFile>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
    QSettings *settings;

private slots:
    void login();
    void saveSettings();
    void loadSettings();

    void display_psd(bool checked);

private:
    Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H

5.串口界面

serial.h预定义串口相关功能函数,导入串口的库文件

#ifndef SERIAL_H
#define SERIAL_H

#include <QMainWindow>
#include <QSerialPort>
#include <QString>
#include <QSerialPortInfo>
#include <QMessageBox>
#include <QTimer>
#include <QTime>
#include <QPainter>
#include <QDebug>
namespace Ui {
class Serial;
}

class Serial : public QMainWindow
{
    Q_OBJECT

public:
    explicit Serial(QWidget *parent = nullptr);
    ~Serial();
    QSerialPort *serialPort;//定义串口指针


private slots:
    //    void on_button_openserial_clicked();

    /*手动连接槽函数*/
    void manual_serialPortReadyRead();

    void on_chkTimSend_stateChanged(int arg1);
    /*以下为mainwindow.ui文件中点击“转到槽”自动生成的函数*/
    void on_Serial_check_Bt_clicked();

    void on_open_serial_Bt_clicked();

    void on_send_Bt_clicked();

    void on_clear_recv_Bt_clicked();

    void on_clear_send_Bt_clicked();
private:
    Ui::Serial *ui;
    // 发送、接收字节计数
    long sendNum, recvNum;
    QLabel *lblSendNum;
    QLabel *lblRecvNum;
    QLabel *lblPortState;
    void setNumOnLabel(QLabel *lbl, QString strS, long num);

    // 定时发送-定时器
    QTimer *timSend;

};

#endif // SERIAL_H

serial.cpp实现定义串口相关功能函数

#include "serial.h"
#include "ui_serial.h"
#include "QSerialPortInfo"
#include <QSerialPort>
#include <QMessageBox>
#include <QDateTime>
#include <QStatusBar>
Serial::Serial(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::Serial)
{
    ui->setupUi(this);
    QStringList serialNamePort;
    serialPort = new QSerialPort(this);
    connect(serialPort,SIGNAL(readyRead()),this,SLOT(manual_serialPortReadyRead()));/*手动连接槽函数*/

    /*找出当前连接的串口并显示到serailCb*/
    on_Serial_check_Bt_clicked();

    // 发送、接收计数清零
    sendNum = 0;
    recvNum = 0;
    // 状态栏
    QStatusBar *sBar = statusBar();
    // 状态栏的收、发计数标签
    lblSendNum = new QLabel(this);
    lblRecvNum = new QLabel(this);
    lblPortState = new QLabel(this);
    lblPortState->setText("Connected");
    //设置串口状态标签为绿色 表示已连接状态
    lblPortState->setStyleSheet("color:red");

    // 设置标签最小大小
    lblSendNum->setMinimumSize(100, 20);
    lblRecvNum->setMinimumSize(100, 20);
    lblPortState->setMinimumSize(550, 20);
    setNumOnLabel(lblSendNum, "S: ", sendNum);
    setNumOnLabel(lblRecvNum, "R: ", recvNum);
    // 从右往左依次添加
    sBar->addPermanentWidget(lblPortState);
    sBar->addPermanentWidget(lblSendNum);
    sBar->addPermanentWidget(lblRecvNum);

    // 定时发送-定时器
    timSend = new QTimer;
    timSend->setInterval(1000);// 设置默认定时时长1000ms
    connect(timSend, &QTimer::timeout, this, [=](){on_send_Bt_clicked();});

}

Serial::~Serial()
{
    if(ui != nullptr){
        delete ui;
        delete serialPort;
        delete timSend;
        delete lblSendNum;
        delete lblRecvNum;
        delete lblPortState;
    }

}




void Serial::on_Serial_check_Bt_clicked()
{
    ui->serial_Cb->clear();
    //通过QSerialPortInfo查找可用串口
    foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
    {
        ui->serial_Cb->addItem(info.portName());
    }

}


void Serial::on_open_serial_Bt_clicked()
{
    /*串口初始化*/
    QSerialPort::BaudRate baudRate;
    QSerialPort::DataBits dataBits;
    QSerialPort::StopBits stopBits;
    QSerialPort::Parity checkBits;
    baudRate=QSerialPort::Baud9600;
    dataBits=QSerialPort::Data8;
    stopBits=QSerialPort::OneStop;
    checkBits = QSerialPort::NoParity;
    // 获取串口波特率
    // baudRate = ui->baundrate_Cb->currentText().toInt();直接字符串转换为 int 的方法

    if(ui->baundrate_Cb->currentText()=="1200")
        baudRate=QSerialPort::Baud1200;
    else if(ui->baundrate_Cb->currentText()=="2400")
        baudRate=QSerialPort::Baud2400;
    else if(ui->baundrate_Cb->currentText()=="4800")
        baudRate=QSerialPort::Baud4800;
    else if(ui->baundrate_Cb->currentText()=="9600")
        baudRate=QSerialPort::Baud9600;
    else if(ui->baundrate_Cb->currentText()=="19200")
        baudRate=QSerialPort::Baud19200;
    else if(ui->baundrate_Cb->currentText()=="38400")
        baudRate=QSerialPort::Baud38400;
    else if(ui->baundrate_Cb->currentText()=="57600")
        baudRate=QSerialPort::Baud57600;
    else if(ui->baundrate_Cb->currentText()=="115200")
        baudRate=QSerialPort::Baud115200;

    // 获取串口数据位
    if(ui->databit_Cb->currentText()=="5")
        dataBits=QSerialPort::Data5;
    else if(ui->databit_Cb->currentText()=="6")
        dataBits=QSerialPort::Data6;
    else if(ui->databit_Cb->currentText()=="7")
        dataBits=QSerialPort::Data7;
    else if(ui->databit_Cb->currentText()=="8")
        dataBits=QSerialPort::Data8;

    // 获取串口停止位
    if(ui->stopbit_Cb->currentText()=="1")
        stopBits=QSerialPort::OneStop;
    else if(ui->stopbit_Cb->currentText()=="1.5")
        stopBits=QSerialPort::OneAndHalfStop;
    else if(ui->stopbit_Cb->currentText()=="2")
        stopBits=QSerialPort::TwoStop;

    // 获取串口奇偶校验位
    if(ui->checkbit_Cb->currentText() == "none"){
        checkBits = QSerialPort::NoParity;
    }else if(ui->checkbit_Cb->currentText() == "奇校验"){
        checkBits = QSerialPort::OddParity;
    }else if(ui->checkbit_Cb->currentText() == "偶校验"){
        checkBits = QSerialPort::EvenParity;
    }

    // 初始化串口属性,设置 端口号、波特率、数据位、停止位、奇偶校验位数
    serialPort->setPortName(ui->serial_Cb->currentText());
    serialPort->setBaudRate(baudRate);
    serialPort->setDataBits(dataBits);
    serialPort->setStopBits(stopBits);
    serialPort->setParity(checkBits);

    // 根据初始化好的串口属性,打开串口
    // 如果打开成功,反转打开按钮显示和功能。打开失败,无变化,并且弹出错误对话框。
    if(ui->open_serial_Bt->text() == "打开串口"){
        if(serialPort->open(QIODevice::ReadWrite) == true){
            //QMessageBox::
            ui->open_serial_Bt->setText("关闭串口");
            // 让端口号下拉框不可选,避免误操作(选择功能不可用,控件背景为灰色)
            ui->serial_Cb->setEnabled(false);
        }else{
            QMessageBox::critical(this, "错误提示", "串口打开失败!!!\r\n该串口可能被占用\r\n请选择正确的串口");
        }
        //statusBar 状态栏显示端口状态
        QString sm = "%1 OPENED, %2, 8, NONE, 1";
        QString status = sm.arg(serialPort->portName()).arg(serialPort->baudRate());
        lblPortState->setText(status);
        lblPortState->setStyleSheet("color:green");
    }else{
        serialPort->close();
        ui->open_serial_Bt->setText("打开串口");
        // 端口号下拉框恢复可选,避免误操作
        ui->serial_Cb->setEnabled(true);
        //statusBar 状态栏显示端口状态
        QString sm = "%1 CLOSED";
        QString status = sm.arg(serialPort->portName());
        lblPortState->setText(status);
        lblPortState->setStyleSheet("color:red");
    }

}


void Serial::on_send_Bt_clicked()
{
    QByteArray array;

    //Hex复选框
    if(ui->send_hex_Chb->checkState() == Qt::Checked){
        //array = QString2Hex(data);  //HEX 16进制
        array = QByteArray::fromHex(ui->textEdit_send->toPlainText().toUtf8()).data();
    }else{
        //array = data.toLatin1();    //ASCII
        array = ui->textEdit_send->toPlainText().toLocal8Bit().data();
    }

    if(ui->send_line_Chb->checkState() == Qt::Checked){
        array.append("\r\n");
    }
    // 如发送成功,会返回发送的字节长度。失败,返回-1。
    int a = serialPort->write(array);
    // 发送字节计数并显示
    if(a > 0)
    {
        // 发送字节计数
        sendNum += a;
        // 状态栏显示计数值
        setNumOnLabel(lblSendNum, "S: ", sendNum);
    }
}


void Serial::on_clear_recv_Bt_clicked()
{
    ui->textEdit_recv->clear();
    // 清除接收字节计数
    sendNum = 0;
    // 状态栏显示计数值
    setNumOnLabel(lblSendNum, "S: ", sendNum);
}


void Serial::on_clear_send_Bt_clicked()
{
    ui->textEdit_send->clear();
    // 清除发送字节计数
    sendNum = 0;
    // 状态栏显示计数值
    setNumOnLabel(lblSendNum, "S: ", sendNum);
}

// 定时发送开关 选择复选框
void Serial::on_chkTimSend_stateChanged(int arg1)
{
    // 获取复选框状态,未选为0,选中为2
    if(arg1 == 0){
        timSend->stop();
        // 时间输入框恢复可选
        ui->txtSendMs->setEnabled(true);
    }else{
        // 对输入的值做限幅,小于10ms会弹出对话框提示
        if(ui->txtSendMs->text().toInt() >= 10){
            timSend->start(ui->txtSendMs->text().toInt());// 设置定时时长,重新计数
            // 让时间输入框不可选,避免误操作(输入功能不可用,控件背景为灰色)
            ui->txtSendMs->setEnabled(false);
        }else{
            ui->autosend_Chb->setCheckState(Qt::Unchecked);
            QMessageBox::critical(this, "错误提示", "定时发送的最小间隔为 10ms\r\n请确保输入的值 >=10");
        }
    }
}



/*手动实现接收数据函数*/
void Serial::manual_serialPortReadyRead()
{
    QByteArray recBuf = serialPort->readAll();

    QString str_rev;

    // 接收字节计数
    recvNum += recBuf.size();
    // 状态栏显示计数值
    setNumOnLabel(lblRecvNum, "R: ", recvNum);

    if(ui->recv_hex_Chb->checkState() == false){
        if(ui->recv_time_Chb->checkState() == Qt::Checked){
            QDateTime nowtime = QDateTime::currentDateTime();
            str_rev = "[" + nowtime.toString("yyyy-MM-dd hh:mm:ss") + "] ";
            str_rev += QString(recBuf).append("\r\n");
        }
        else{
            // 在当前位置插入文本,不会发生换行。如果没有移动光标到文件结尾,会导致文件超出当前界面显示范围,界面也不会向下滚动。
            //ui->recvEdit->appendPlainText(buf);

            if(ui->recv_autoline_Chb->checkState() == Qt::Checked){
                str_rev = QString(recBuf).append("\r\n");
            }
            else
            {
                str_rev = QString(recBuf);
            }
        }
    }else{

        // 16进制显示,并转换为大写
        QString str1 = recBuf.toHex().toUpper();//.data();
        // 添加空格
        QString str2;
        for(int i = 0; i<str1.length (); i+=2)
        {
            str2 += str1.midRef (i,2);
            str2 += " ";
        }
        if(ui->recv_time_Chb->checkState() == Qt::Checked)
        {
            QDateTime nowtime = QDateTime::currentDateTime();
            str_rev = "[" + nowtime.toString("yyyy-MM-dd hh:mm:ss") + "] ";
            str_rev += str2.append("\r\n");
        }
        else
        {
            if(ui->recv_autoline_Chb->checkState() == Qt::Checked)
                str_rev += str2.append("\r\n");
            else
                str_rev = str2;

        }
    }
    ui->textEdit_recv->insertPlainText(str_rev);
    ui->textEdit_recv->moveCursor(QTextCursor::End);

}


// 状态栏标签显示计数值
void Serial::setNumOnLabel(QLabel *lbl, QString strS, long num)
{
    // 标签显示
    QString strN;
    strN.sprintf("%ld", num);
    QString str = strS + strN;
    lbl->setText(str);
}


6.测试功能

在这里插入图片描述
运行此代码,弹出登录界面
在这里插入图片描述

输入用户密码
admin123456
user111111

这里有两个账号,点击记住密码,下次就可以不输入密码直接登录就接入串口界面
在这里插入图片描述

在这里插入图片描述
然后配置串口参数打开串口,这就可以正常收发啦!

7.总结

以上就是使用Qt实现基本的用户登录以及界面跳转的过程。实际开发过程中,你可能还需要考虑更多细节,比如数据加密存储、网络通信安全等。此外,对于多窗口的应用程序,良好的架构设计有助于管理不同窗口之间的交互和状态维护。
🛹🛹🛹从而实现对外部世界进行感知,充分认识这个有机与无机的环境🥳🥳🥳科学地合理地进行创作和发挥效益,然后为人类社会发展贡献一点微薄之力。🤣🤣🤣

如果你有任何问题,可以通过下面的二维码加入鹏鹏小分队,期待与你思维的碰撞😘😘😘

参考文献:
相关好文推荐:

  1. QT初体验:手把手带你写一个自己的串口助手
  2. 【Qt安装与简易串口控制Arduino开发板小灯教程】
  3. 【QT串口助手】

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2278937.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【docker踩坑记录】

docker踩坑记录 踩坑记录(持续更新中.......)docker images 权限问题 踩坑记录(持续更新中…) docker images 权限问题 permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Head "http://%2Fvar%2Frun%2Fdocker.s…

搜维尔科技:Xsens人形机器人解决方案的优势

Xsens 致力于推动人形机器人技术的发展&#xff0c;塑造机器人与人类环境无缝融合的未来&#xff0c;通过创新精确和协作&#xff0c;协助生产和服务&#xff0c;改善人类生活和产业。 Xsens通过人形跟随捕捉详细的人体运动数据&#xff0c;使机器人能够学习类人的动作&#x…

国内微电子(集成电路)领域重点高校的特色与优势

本文旨在梳理国内微电子&#xff08;集成电路&#xff09;领域重点高校的特色与优势&#xff0c;为有志于从事相关领域的学生提供参考。文章将从学科特色、科研实力&#xff08;以ISSCC论文为参考之一&#xff09;、行业认可度等方面进行分析&#xff0c;并强调实验室、导师、研…

leetcode707-设计链表

leetcode 707 思路 本题也是用了虚拟头节点来进行解答&#xff0c;这样的好处是&#xff0c;不管是头节点还是中间的节点都可以当成是中间节点来处理&#xff0c;用同一套方法就可以进行处理&#xff0c;而不用考虑太多的边界条件。 下面题目中最主要的实现就是添加操作addA…

数据结构-栈队列OJ题

文章目录 一、有效的括号二、用队列实现栈三、用栈实现队列四、设计循环队列 一、有效的括号 (链接&#xff1a;ValidParentheses) 这道题用栈这种数据结构解决最好&#xff0c;因为栈有后进先出的性质。简单分析一下这道题&#xff1a;所给字符串不是空的也就是一定至少存在一…

MindAgent:基于大型语言模型的多智能体协作基础设施

2023-09-18 &#xff0c;加州大学洛杉矶分校&#xff08;UCLA&#xff09;、微软研究院、斯坦福大学等机构共同创建的新型基础设施&#xff0c;目的在评估大型语言模型在游戏互动中的规划和协调能力。MindAgent通过CuisineWorld这一新的游戏场景和相关基准&#xff0c;调度多智…

近红外简单ROI分析matlab(NIRS_SPM)

本次笔记主要想验证上篇近红外分析是否正确&#xff0c;因为叠加平均有不同的计算方法&#xff0c;一种是直接将每个通道的5分钟实时长单独进行叠加平均&#xff0c;另一种是将通道划分为1分钟的片段&#xff0c;将感兴趣的通道数据进行对应叠加平均&#xff0c;得到一个总平均…

开发神器之cursor

文章目录 cursor简介主要特点 下载cursor页面的简单介绍切换大模型指定ai学习的文件指定特定的代码喂给ai创建项目框架文件 cursor简介 Cursor 是一款专为开发者设计的智能代码编辑器&#xff0c;集成了先进的 AI 技术&#xff0c;旨在提升编程效率。以下是其主要特点和功能&a…

电脑风扇声音大怎么办? 原因及解决方法

电脑风扇是电脑的重要组件之一&#xff0c;它的作用是为电脑的各个部件提供冷却&#xff0c;防止电脑过热。然而&#xff0c;有时候我们会发现电脑风扇的声音特别大&#xff0c;不仅影响我们的使用体验&#xff0c;也可能是电脑出现了一些问题。那么&#xff0c;电脑风扇声音大…

SpringBoot错误码国际化

先看测试效果&#xff1a; 1. 设置中文 2.设置英文 文件结构 1.中文和英文的错误消息配置 package com.ldj.mybatisflex.common;import lombok.Getter;/*** User: ldj* Date: 2025/1/12* Time: 17:50* Description: 异常消息枚举*/ Getter public enum ExceptionEnum {//…

软考高级5个资格、中级常考4个资格简介及难易程度排序

一、软考高级5个资格 01、网络规划设计师 资格简介&#xff1a;网络规划设计师要求考生具备全面的网络规划、设计、部署和管理能力&#xff1b;该资格考试适合那些在网络规划和设计方面具有较好理论基础和较丰富从业经验的人员参加。 02、系统分析师 资格简介&#xff1a;系统分…

如何通过 Apache Airflow 将数据导入 Elasticsearch

作者&#xff1a;来自 Elastic Andre Luiz 了解如何通过 Apache Airflow 将数据导入 Elasticsearch。 Apache Airflow Apache Airflow 是一个旨在创建、安排&#xff08;schedule&#xff09;和监控工作流的平台。它用于编排 ETL&#xff08;Extract-Transform-Load&#xff0…

STM32 学习笔记【补充】(十)硬件I2C读写MPU6050

该系列为笔者在学习STM32过程&#xff08;主线是江科大的视频&#xff09;中的记录与发散思考。 初学难免有所纰漏、错误&#xff0c;还望大家不吝指正&#xff0c;感谢~ 一、I2C 外设简介 I2C&#xff08;Inter-Integrated Circuit&#xff09;是一种多主多从的串行通信协议…

QT信号槽 笔记

信号与槽就是QT中处理计算机外设响应的一种机制 比如敲击键盘、点击鼠标 // 举例&#xff1a; 代码&#xff1a; connect(ls,SIGNAL(sig_chifanla()),ww,SLOT(slot_quchifan())); connect(ls,SIGNAL(sig_chifanla()),zl,SLOT(slot_quchifan()));connect函数&#xff1a;这是…

【React】插槽渲染机制

目录 通过 children 属性结合条件渲染通过 children 和 slot 属性实现具名插槽通过 props 实现具名插槽 在 React 中&#xff0c;并没有直接类似于 Vue 中的“插槽”机制&#xff08;slot&#xff09;。但是&#xff0c;React 可以通过 props和 children 来实现类似插槽的功能…

openharmony电源管理子系统

电源管理子系统 简介目录使用说明相关仓 简介 电源管理子系统提供如下功能&#xff1a; 重启服务&#xff1a;系统重启和下电。系统电源管理服务&#xff1a;系统电源状态管理和休眠运行锁管理。显示相关的能耗调节&#xff1a;包括根据环境光调节背光亮度&#xff0c;和根…

数据库(中)11讲

用颜色、有否下划线对应&#xff01; E-R图

图像去雾数据集的下载和预处理操作

前言 目前&#xff0c;因为要做对比实验&#xff0c;收集了一下去雾数据集&#xff0c;并且建立了一个数据集的预处理工程。 这是以前我写的一个小仓库&#xff0c;我决定还是把它用起来&#xff0c;下面将展示下载的路径和数据处理的方法。 下面的代码均可以在此找到。Auo…

STM32入门教程-示例程序(按键控制LED光敏传感器控制蜂鸣器)

1. LED Blink&#xff08;闪烁&#xff09; 代码主体包含&#xff1a;LED.c key.c main.c delay.c&#xff08;延时防按键抖动&#xff09; 程序代码如下&#xff08;涉及RCC与GPIO两个外设&#xff09;&#xff1a; 1.使用RCC使能GPIO时钟 RCC_APB2PeriphClockC…

一本书揭秘程序员如何培养架构思维!

在程序员的职业规划中&#xff0c;成为软件架构师是一个非常有吸引力的选择。但是对于如何才能成为一名架构师&#xff0c;不少同学认为只要代码写得好&#xff0c;就能得到公司提拔&#xff0c;晋升为架构师。 还真不是这样的&#xff0c;如果不具备架构思维&#xff0c;即使…