Qt触摸屏应用实例

Qt触摸屏应用实例,包含触摸事件处理、虚拟键盘、手势识别和响应式界面设计。

一、项目结构

复制代码
QtTouchScreenDemo/
├── main.cpp                 # 程序入口
├── MainWindow.h            # 主窗口头文件
├── MainWindow.cpp          # 主窗口实现
├── TouchWidget.h           # 触摸控件头文件
├── TouchWidget.cpp         # 触摸控件实现
├── VirtualKeyboard.h       # 虚拟键盘头文件
├── VirtualKeyboard.cpp     # 虚拟键盘实现
├── GestureArea.h           # 手势区域头文件
├── GestureArea.cpp         # 手势区域实现
├── resources.qrc           # 资源文件
└── QtTouchScreenDemo.pro   # Qt项目文件

二、核心源码实现

2.1 Qt项目文件 (QtTouchScreenDemo.pro)

qmake 复制代码
QT += core gui widgets

CONFIG += c++11

TARGET = QtTouchScreenDemo
TEMPLATE = app

SOURCES += \
    main.cpp \
    MainWindow.cpp \
    TouchWidget.cpp \
    VirtualKeyboard.cpp \
    GestureArea.cpp

HEADERS += \
    MainWindow.h \
    TouchWidget.h \
    VirtualKeyboard.h \
    GestureArea.h

RESOURCES += \
    resources.qrc

# 触摸屏支持
QT += gui-private
DEFINES += QT_ENABLE_HOVERING

2.2 程序入口 (main.cpp)

cpp 复制代码
#include "MainWindow.h"
#include <QApplication>
#include <QStyleFactory>
#include <QFontDatabase>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    
    // 设置应用程序属性
    app.setApplicationName("Qt触摸屏演示");
    app.setApplicationVersion("1.0");
    app.setOrganizationName("QtDemo");
    
    // 设置样式
    app.setStyle(QStyleFactory::create("Fusion"));
    
    // 设置字体
    QFont font("Microsoft YaHei", 12);
    app.setFont(font);
    
    // 设置触摸屏属性
    app.setAttribute(Qt::AA_EnableHighDpiScaling);
    app.setAttribute(Qt::AA_UseHighDpiPixmaps);
    
    // 创建并显示主窗口
    MainWindow window;
    window.showFullScreen();  // 全屏显示,适合触摸屏
    
    return app.exec();
}

2.3 主窗口头文件 (MainWindow.h)

cpp 复制代码
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QStackedWidget>
#include <QPushButton>
#include <QLabel>
#include <QStatusBar>
#include "VirtualKeyboard.h"
#include "GestureArea.h"

class MainWindow : public QMainWindow
{
    Q_OBJECT

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

private slots:
    void onHomeClicked();
    void onKeyboardClicked();
    void onGestureClicked();
    void onSettingsClicked();
    void onExitClicked();
    void updateTouchInfo(const QString &info);

private:
    void createNavigation();
    void createCentralWidget();
    void createStatusBar();
    void setupConnections();

private:
    QStackedWidget *stackedWidget;
    QWidget *homeWidget;
    QWidget *keyboardWidget;
    QWidget *gestureWidget;
    QWidget *settingsWidget;
    
    QPushButton *homeBtn;
    QPushButton *keyboardBtn;
    QPushButton *gestureBtn;
    QPushButton *settingsBtn;
    QPushButton *exitBtn;
    
    QLabel *statusLabel;
    QLabel *touchInfoLabel;
    
    VirtualKeyboard *virtualKeyboard;
    GestureArea *gestureArea;
};

#endif // MAINWINDOW_H

2.4 主窗口实现 (MainWindow.cpp)

cpp 复制代码
#include "MainWindow.h"
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QGridLayout>
#include <QFrame>
#include <QGroupBox>
#include <QLineEdit>
#include <QTextEdit>
#include <QSlider>
#include <QSpinBox>
#include <QCheckBox>
#include <QComboBox>
#include <QDateTime>
#include <QTimer>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    setWindowTitle("Qt触摸屏演示系统");
    resize(1024, 768);
    
    // 创建UI组件
    createNavigation();
    createCentralWidget();
    createStatusBar();
    setupConnections();
    
    // 设置初始页面
    stackedWidget->setCurrentWidget(homeWidget);
}

MainWindow::~MainWindow()
{
}

void MainWindow::createNavigation()
{
    // 创建导航栏
    QWidget *navWidget = new QWidget(this);
    navWidget->setFixedHeight(80);
    navWidget->setStyleSheet("background-color: #2c3e50;");
    
    homeBtn = new QPushButton("主页", navWidget);
    keyboardBtn = new QPushButton("虚拟键盘", navWidget);
    gestureBtn = new QPushButton("手势识别", navWidget);
    settingsBtn = new QPushButton("设置", navWidget);
    exitBtn = new QPushButton("退出", navWidget);
    
    // 设置按钮样式
    QString buttonStyle = "QPushButton {"
                          "background-color: #3498db;"
                          "color: white;"
                          "border: none;"
                          "padding: 15px 30px;"
                          "font-size: 16px;"
                          "border-radius: 5px;"
                          "}"
                          "QPushButton:hover { background-color: #2980b9; }"
                          "QPushButton:pressed { background-color: #1abc9c; }";
    
    homeBtn->setStyleSheet(buttonStyle);
    keyboardBtn->setStyleSheet(buttonStyle);
    gestureBtn->setStyleSheet(buttonStyle);
    settingsBtn->setStyleSheet(buttonStyle);
    exitBtn->setStyleSheet(buttonStyle);
    
    // 布局
    QHBoxLayout *navLayout = new QHBoxLayout(navWidget);
    navLayout->addWidget(homeBtn);
    navLayout->addWidget(keyboardBtn);
    navLayout->addWidget(gestureBtn);
    navLayout->addWidget(settingsBtn);
    navLayout->addStretch();
    navLayout->addWidget(exitBtn);
    navLayout->setContentsMargins(20, 10, 20, 10);
    
    setMenuWidget(navWidget);
}

void MainWindow::createCentralWidget()
{
    stackedWidget = new QStackedWidget(this);
    setCentralWidget(stackedWidget);
    
    // 创建各个页面
    createHomeWidget();
    createKeyboardWidget();
    createGestureWidget();
    createSettingsWidget();
}

void MainWindow::createHomeWidget()
{
    homeWidget = new QWidget(stackedWidget);
    
    QVBoxLayout *layout = new QVBoxLayout(homeWidget);
    
    // 标题
    QLabel *titleLabel = new QLabel("Qt触摸屏演示系统", homeWidget);
    titleLabel->setAlignment(Qt::AlignCenter);
    titleLabel->setStyleSheet("font-size: 36px; font-weight: bold; color: #2c3e50; margin: 30px;");
    
    // 时间显示
    QLabel *timeLabel = new QLabel(homeWidget);
    timeLabel->setAlignment(Qt::AlignCenter);
    timeLabel->setStyleSheet("font-size: 24px; color: #7f8c8d; margin-bottom: 30px;");
    
    // 更新时间
    QTimer *timer = new QTimer(this);
    connect(timer, &QTimer::timeout,  {
        timeLabel->setText(QDateTime::currentDateTime().toString("yyyy年MM月dd日 hh:mm:ss"));
    });
    timer->start(1000);
    timer->timeout(); // 立即更新一次
    
    // 功能卡片
    QGridLayout *cardLayout = new QGridLayout();
    
    QStringList cardTitles = {"虚拟键盘", "手势识别", "触摸绘图", "多点触控", "压力感应", "校准设置"};
    QStringList cardColors = {"#3498db", "#2ecc71", "#e74c3c", "#f39c12", "#9b59b6", "#1abc9c"};
    
    for (int i = 0; i < cardTitles.size(); ++i) {
        QPushButton *card = new QPushButton(cardTitles[i], homeWidget);
        card->setFixedSize(200, 150);
        card->setStyleSheet(QString("QPushButton {"
                                   "background-color: %1;"
                                   "color: white;"
                                   "border-radius: 10px;"
                                   "font-size: 18px;"
                                   "font-weight: bold;"
                                   "}"
                                   "QPushButton:hover {"
                                   "background-color: %2;"
                                   "}").arg(cardColors[i]).arg(cardColors[i].replace("#", "#FF")));
        
        cardLayout->addWidget(card, i / 3, i % 3);
        
        // 连接信号
        if (i == 0) connect(card, &QPushButton::clicked, this, &MainWindow::onKeyboardClicked);
        if (i == 1) connect(card, &QPushButton::clicked, this, &MainWindow::onGestureClicked);
    }
    
    layout->addWidget(titleLabel);
    layout->addWidget(timeLabel);
    layout->addLayout(cardLayout);
    layout->addStretch();
    
    stackedWidget->addWidget(homeWidget);
}

void MainWindow::createKeyboardWidget()
{
    keyboardWidget = new QWidget(stackedWidget);
    
    QVBoxLayout *layout = new QVBoxLayout(keyboardWidget);
    
    // 标题
    QLabel *titleLabel = new QLabel("虚拟键盘演示", keyboardWidget);
    titleLabel->setAlignment(Qt::AlignCenter);
    titleLabel->setStyleSheet("font-size: 28px; font-weight: bold; color: #2c3e50; margin: 20px;");
    
    // 输入框
    QLineEdit *lineEdit = new QLineEdit(keyboardWidget);
    lineEdit->setPlaceholderText("点击此处弹出虚拟键盘...");
    lineEdit->setStyleSheet("QLineEdit {"
                           "padding: 15px;"
                           "font-size: 18px;"
                           "border: 2px solid #bdc3c7;"
                           "border-radius: 5px;"
                           "margin: 10px 50px;"
                           "}");
    
    // 文本编辑框
    QTextEdit *textEdit = new QTextEdit(keyboardWidget);
    textEdit->setPlaceholderText("在此输入多行文本...");
    textEdit->setStyleSheet("QTextEdit {"
                            "padding: 15px;"
                            "font-size: 16px;"
                            "border: 2px solid #bdc3c7;"
                            "border-radius: 5px;"
                            "margin: 10px 50px;"
                            "}");
    
    // 创建虚拟键盘
    virtualKeyboard = new VirtualKeyboard(keyboardWidget);
    virtualKeyboard->hide();
    
    // 连接信号
    connect(lineEdit, &QLineEdit::cursorPositionChanged,  {
        virtualKeyboard->show();
    });
    connect(textEdit, &QTextEdit::cursorPositionChanged,  {
        virtualKeyboard->show();
    });
    connect(virtualKeyboard, &VirtualKeyboard::keyPressed, lineEdit, &QLineEdit::insert);
    connect(virtualKeyboard, &VirtualKeyboard::keyPressed, textEdit, &QTextEdit::insertPlainText);
    connect(virtualKeyboard, &VirtualKeyboard::backspacePressed,  {
        if (lineEdit->hasFocus()) {
            lineEdit->backspace();
        } else if (textEdit->hasFocus()) {
            textEdit->textCursor().deletePreviousChar();
        }
    });
    
    layout->addWidget(titleLabel);
    layout->addWidget(lineEdit);
    layout->addWidget(textEdit);
    layout->addWidget(virtualKeyboard);
    
    stackedWidget->addWidget(keyboardWidget);
}

void MainWindow::createGestureWidget()
{
    gestureWidget = new QWidget(stackedWidget);
    
    QVBoxLayout *layout = new QVBoxLayout(gestureWidget);
    
    // 标题
    QLabel *titleLabel = new QLabel("手势识别演示", gestureWidget);
    titleLabel->setAlignment(Qt::AlignCenter);
    titleLabel->setStyleSheet("font-size: 28px; font-weight: bold; color: #2c3e50; margin: 20px;");
    
    // 创建手势区域
    gestureArea = new GestureArea(gestureWidget);
    gestureArea->setMinimumHeight(400);
    gestureArea->setStyleSheet("background-color: #ecf0f1; border: 2px dashed #bdc3c7; border-radius: 10px; margin: 20px;");
    
    // 手势信息显示
    touchInfoLabel = new QLabel("手势信息将显示在这里", gestureWidget);
    touchInfoLabel->setAlignment(Qt::AlignCenter);
    touchInfoLabel->setStyleSheet("font-size: 16px; color: #7f8c8d; padding: 10px;");
    
    layout->addWidget(titleLabel);
    layout->addWidget(gestureArea);
    layout->addWidget(touchInfoLabel);
    
    // 连接信号
    connect(gestureArea, &GestureArea::gestureDetected, this, &MainWindow::updateTouchInfo);
    
    stackedWidget->addWidget(gestureWidget);
}

void MainWindow::createSettingsWidget()
{
    settingsWidget = new QWidget(stackedWidget);
    
    QVBoxLayout *layout = new QVBoxLayout(settingsWidget);
    
    // 标题
    QLabel *titleLabel = new QLabel("系统设置", settingsWidget);
    titleLabel->setAlignment(Qt::AlignCenter);
    titleLabel->setStyleSheet("font-size: 28px; font-weight: bold; color: #2c3e50; margin: 20px;");
    
    // 设置组
    QGroupBox *touchGroup = new QGroupBox("触摸设置", settingsWidget);
    QVBoxLayout *touchLayout = new QVBoxLayout(touchGroup);
    
    QCheckBox *touchFeedback = new QCheckBox("触摸反馈", touchGroup);
    touchFeedback->setChecked(true);
    QCheckBox *touchSound = new QCheckBox("触摸声音", touchGroup);
    touchSound->setChecked(false);
    QCheckBox *multiTouch = new QCheckBox("多点触控", touchGroup);
    multiTouch->setChecked(true);
    
    touchLayout->addWidget(touchFeedback);
    touchLayout->addWidget(touchSound);
    touchLayout->addWidget(multiTouch);
    
    // 灵敏度设置
    QGroupBox *sensitivityGroup = new QGroupBox("灵敏度设置", settingsWidget);
    QVBoxLayout *sensitivityLayout = new QVBoxLayout(sensitivityGroup);
    
    QLabel *sliderLabel = new QLabel("触摸灵敏度:", sensitivityGroup);
    QSlider *sensitivitySlider = new QSlider(Qt::Horizontal, sensitivityGroup);
    sensitivitySlider->setRange(1, 100);
    sensitivitySlider->setValue(80);
    
    sensitivityLayout->addWidget(sliderLabel);
    sensitivityLayout->addWidget(sensitivitySlider);
    
    // 校准按钮
    QPushButton *calibrateBtn = new QPushButton("触摸屏校准", settingsWidget);
    calibrateBtn->setStyleSheet("QPushButton {"
                               "background-color: #e74c3c;"
                               "color: white;"
                               "padding: 15px;"
                               "font-size: 16px;"
                               "border-radius: 5px;"
                               "margin-top: 20px;"
                               "}");
    
    layout->addWidget(titleLabel);
    layout->addWidget(touchGroup);
    layout->addWidget(sensitivityGroup);
    layout->addWidget(calibrateBtn);
    layout->addStretch();
    
    stackedWidget->addWidget(settingsWidget);
}

void MainWindow::createStatusBar()
{
    statusLabel = new QLabel("就绪", this);
    statusLabel->setStyleSheet("padding: 5px;");
    
    QStatusBar *statusBar = new QStatusBar(this);
    statusBar->addWidget(statusLabel);
    setStatusBar(statusBar);
}

void MainWindow::setupConnections()
{
    connect(homeBtn, &QPushButton::clicked, this, &MainWindow::onHomeClicked);
    connect(keyboardBtn, &QPushButton::clicked, this, &MainWindow::onKeyboardClicked);
    connect(gestureBtn, &QPushButton::clicked, this, &MainWindow::onGestureClicked);
    connect(settingsBtn, &QPushButton::clicked, this, &MainWindow::onSettingsClicked);
    connect(exitBtn, &QPushButton::clicked, this, &MainWindow::onExitClicked);
}

void MainWindow::onHomeClicked()
{
    stackedWidget->setCurrentWidget(homeWidget);
    statusLabel->setText("主页");
}

void MainWindow::onKeyboardClicked()
{
    stackedWidget->setCurrentWidget(keyboardWidget);
    statusLabel->setText("虚拟键盘演示");
}

void MainWindow::onGestureClicked()
{
    stackedWidget->setCurrentWidget(gestureWidget);
    statusLabel->setText("手势识别演示");
}

void MainWindow::onSettingsClicked()
{
    stackedWidget->setCurrentWidget(settingsWidget);
    statusLabel->setText("系统设置");
}

void MainWindow::onExitClicked()
{
    close();
}

void MainWindow::updateTouchInfo(const QString &info)
{
    touchInfoLabel->setText(info);
    statusLabel->setText(info);
}

2.5 触摸控件头文件 (TouchWidget.h)

cpp 复制代码
#ifndef TOUCHWIDGET_H
#define TOUCHWIDGET_H

#include <QWidget>
#include <QTouchEvent>
#include <QPainter>
#include <QVector>
#include <QPoint>

struct TouchPoint {
    QPoint position;
    int id;
    Qt::TouchPointState state;
    double pressure;
};

class TouchWidget : public QWidget
{
    Q_OBJECT

public:
    explicit TouchWidget(QWidget *parent = nullptr);
    ~TouchWidget();

protected:
    bool event(QEvent *event) override;
    void paintEvent(QPaintEvent *event) override;
    void mousePressEvent(QMouseEvent *event) override;
    void mouseMoveEvent(QMouseEvent *event) override;
    void mouseReleaseEvent(QMouseEvent *event) override;

signals:
    void touchDetected(const QString &info);

private:
    QVector<TouchPoint> touchPoints;
    bool multiTouchEnabled;
    QColor touchColor;
    
    void handleTouchEvent(QTouchEvent *touchEvent);
    void drawTouchPoints(QPainter &painter);
    QString getTouchInfo() const;
};

#endif // TOUCHWIDGET_H

2.6 触摸控件实现 (TouchWidget.cpp)

cpp 复制代码
#include "TouchWidget.h"
#include <QPainter>
#include <QDebug>

TouchWidget::TouchWidget(QWidget *parent)
    : QWidget(parent)
{
    setAttribute(Qt::WA_AcceptTouchEvents, true);
    setAttribute(Qt::WA_StaticContents);
    setMinimumSize(400, 300);
    
    multiTouchEnabled = true;
    touchColor = QColor(52, 152, 219, 150); // 半透明蓝色
    
    setStyleSheet("background-color: white;");
}

TouchWidget::~TouchWidget()
{
}

bool TouchWidget::event(QEvent *event)
{
    if (event->type() == QEvent::TouchBegin ||
        event->type() == QEvent::TouchUpdate ||
        event->type() == QEvent::TouchEnd) {
        handleTouchEvent(static_cast<QTouchEvent *>(event));
        return true;
    }
    
    return QWidget::event(event);
}

void TouchWidget::handleTouchEvent(QTouchEvent *touchEvent)
{
    touchPoints.clear();
    
    const QList<QTouchEvent::TouchPoint> points = touchEvent->touchPoints();
    
    for (const QTouchEvent::TouchPoint &point : points) {
        TouchPoint tp;
        tp.position = point.pos().toPoint();
        tp.id = point.id();
        tp.state = point.state();
        tp.pressure = point.pressure();
        
        touchPoints.append(tp);
    }
    
    emit touchDetected(getTouchInfo());
    update(); // 触发重绘
}

void TouchWidget::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event);
    
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);
    
    // 绘制背景
    painter.fillRect(rect(), Qt::white);
    
    // 绘制触摸点
    drawTouchPoints(painter);
    
    // 绘制网格
    painter.setPen(QPen(Qt::lightGray, 1));
    for (int x = 0; x < width(); x += 50) {
        painter.drawLine(x, 0, x, height());
    }
    for (int y = 0; y < height(); y += 50) {
        painter.drawLine(0, y, width(), y);
    }
}

void TouchWidget::drawTouchPoints(QPainter &painter)
{
    for (const TouchPoint &tp : touchPoints) {
        QColor color = touchColor;
        
        // 根据触摸状态改变颜色
        switch (tp.state) {
            case Qt::TouchPointPressed:
                color = QColor(46, 204, 113, 200); // 绿色
                break;
            case Qt::TouchPointMoved:
                color = QColor(52, 152, 219, 200); // 蓝色
                break;
            case Qt::TouchPointReleased:
                color = QColor(231, 76, 60, 200); // 红色
                break;
            default:
                break;
        }
        
        // 根据压力改变大小
        int radius = 30 + static_cast<int>(tp.pressure * 20);
        
        painter.setPen(Qt::NoPen);
        painter.setBrush(color);
        painter.drawEllipse(tp.position, radius, radius);
        
        // 绘制触摸点ID
        painter.setPen(Qt::white);
        painter.setFont(QFont("Arial", 12, QFont::Bold));
        painter.drawText(tp.position, QString::number(tp.id));
    }
}

QString TouchWidget::getTouchInfo() const
{
    if (touchPoints.isEmpty()) {
        return "无触摸点";
    }
    
    QString info = QString("检测到 %1 个触摸点\n").arg(touchPoints.size());
    
    for (int i = 0; i < touchPoints.size(); ++i) {
        const TouchPoint &tp = touchPoints[i];
        info += QString("点 %1: (%2, %3) 压力: %4\n")
                .arg(tp.id)
                .arg(tp.position.x())
                .arg(tp.position.y())
                .arg(tp.pressure, 0, 'f', 2);
    }
    
    return info;
}

void TouchWidget::mousePressEvent(QMouseEvent *event)
{
    // 模拟触摸事件
    TouchPoint tp;
    tp.position = event->pos();
    tp.id = 0;
    tp.state = Qt::TouchPointPressed;
    tp.pressure = 1.0;
    
    touchPoints.clear();
    touchPoints.append(tp);
    
    emit touchDetected(getTouchInfo());
    update();
}

void TouchWidget::mouseMoveEvent(QMouseEvent *event)
{
    if (!touchPoints.isEmpty()) {
        touchPoints[0].position = event->pos();
        touchPoints[0].state = Qt::TouchPointMoved;
        emit touchDetected(getTouchInfo());
        update();
    }
}

void TouchWidget::mouseReleaseEvent(QMouseEvent *event)
{
    if (!touchPoints.isEmpty()) {
        touchPoints[0].state = Qt::TouchPointReleased;
        emit touchDetected(getTouchInfo());
        update();
    }
}

2.7 虚拟键盘头文件 (VirtualKeyboard.h)

cpp 复制代码
#ifndef VIRTUALKEYBOARD_H
#define VIRTUALKEYBOARD_H

#include <QWidget>
#include <QPushButton>
#include <QGridLayout>
#include <QSignalMapper>

class VirtualKeyboard : public QWidget
{
    Q_OBJECT

public:
    explicit VirtualKeyboard(QWidget *parent = nullptr);
    ~VirtualKeyboard();

signals:
    void keyPressed(const QString &key);
    void backspacePressed();
    void enterPressed();
    void shiftPressed(bool pressed);
    void capsLockPressed(bool pressed);

private slots:
    void onKeyClicked(const QString &key);

private:
    void createKeys();
    void setupLayout();
    
    QGridLayout *mainLayout;
    QSignalMapper *signalMapper;
    QPushButton *shiftBtn;
    QPushButton *capsLockBtn;
    bool shiftPressed;
    bool capsLockPressed;
    
    QStringList normalKeys;
    QStringList shiftedKeys;
};

#endif // VIRTUALKEYBOARD_H

2.8 虚拟键盘实现 (VirtualKeyboard.cpp)

cpp 复制代码
#include "VirtualKeyboard.h"
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QDebug>

VirtualKeyboard::VirtualKeyboard(QWidget *parent)
    : QWidget(parent)
{
    shiftPressed = false;
    capsLockPressed = false;
    
    // 普通键和Shift键映射
    normalKeys = {
        "`", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "-", "=", "Backspace",
        "Tab", "q", "w", "e", "r", "t", "y", "u", "i", "o", "p", "[", "]", "\\",
        "Caps", "a", "s", "d", "f", "g", "h", "j", "k", "l", ";", "'", "Enter",
        "Shift", "z", "x", "c", "v", "b", "n", "m", ",", ".", "/", "Shift",
        "Ctrl", "Win", "Alt", "Space", "Alt", "Win", "Ctrl"
    };
    
    shiftedKeys = {
        "~", "!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "_", "+", "Backspace",
        "Tab", "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "{", "}", "|",
        "Caps", "A", "S", "D", "F", "G", "H", "J", "K", "L", ":", "\"", "Enter",
        "Shift", "Z", "X", "C", "V", "B", "N", "M", "<", ">", "?", "Shift",
        "Ctrl", "Win", "Alt", "Space", "Alt", "Win", "Ctrl"
    };
    
    createKeys();
    setupLayout();
    
    setMaximumHeight(300);
    setStyleSheet("background-color: #34495e; border-top: 2px solid #2c3e50;");
}

VirtualKeyboard::~VirtualKeyboard()
{
}

void VirtualKeyboard::createKeys()
{
    signalMapper = new QSignalMapper(this);
    
    for (const QString &key : normalKeys) {
        QPushButton *button = new QPushButton(key, this);
        button->setFixedSize(50, 50);
        button->setStyleSheet("QPushButton {"
                             "background-color: #ecf0f1;"
                             "color: #2c3e50;"
                             "border: none;"
                             "border-radius: 5px;"
                             "font-size: 14px;"
                             "}"
                             "QPushButton:hover { background-color: #bdc3c7; }"
                             "QPushButton:pressed { background-color: #95a5a6; }");
        
        connect(button, SIGNAL(clicked()), signalMapper, SLOT(map()));
        signalMapper->setMapping(button, key);
        
        if (key == "Shift") shiftBtn = button;
        if (key == "Caps") capsLockBtn = button;
    }
    
    connect(signalMapper, SIGNAL(mapped(QString)), this, SLOT(onKeyClicked(QString)));
}

void VirtualKeyboard::setupLayout()
{
    mainLayout = new QGridLayout(this);
    mainLayout->setSpacing(5);
    mainLayout->setContentsMargins(10, 10, 10, 10);
    
    int row = 0, col = 0;
    for (const QString &key : normalKeys) {
        if (key == "Space") {
            // 空格键特殊处理
            QPushButton *spaceBtn = findChild<QPushButton *>("Space");
            if (spaceBtn) {
                spaceBtn->setFixedSize(400, 50);
                mainLayout->addWidget(spaceBtn, row, col, 1, 8);
            }
        } else {
            QPushButton *button = findChild<QPushButton *>(key);
            if (button) {
                mainLayout->addWidget(button, row, col);
            }
        }
        
        col++;
        if (col >= 14) {
            col = 0;
            row++;
        }
    }
}

void VirtualKeyboard::onKeyClicked(const QString &key)
{
    if (key == "Backspace") {
        emit backspacePressed();
    } else if (key == "Enter") {
        emit enterPressed();
    } else if (key == "Shift") {
        shiftPressed = !shiftPressed;
        shiftBtn->setStyleSheet(shiftPressed ? 
            "QPushButton { background-color: #3498db; color: white; }" : 
            "QPushButton { background-color: #ecf0f1; color: #2c3e50; }");
        emit shiftPressed(shiftPressed);
    } else if (key == "Caps") {
        capsLockPressed = !capsLockPressed;
        capsLockBtn->setStyleSheet(capsLockPressed ? 
            "QPushButton { background-color: #2ecc71; color: white; }" : 
            "QPushButton { background-color: #ecf0f1; color: #2c3e50; }");
        emit capsLockPressed(capsLockPressed);
    } else if (key == "Space") {
        emit keyPressed(" ");
    } else if (key.length() == 1) {
        QString actualKey = key;
        if (shiftPressed || capsLockPressed) {
            actualKey = shiftedKeys[normalKeys.indexOf(key)];
        }
        emit keyPressed(actualKey);
    }
}

2.9 手势区域头文件 (GestureArea.h)

cpp 复制代码
#ifndef GESTUREAREA_H
#define GESTUREAREA_H

#include <QWidget>
#include <QTouchEvent>
#include <QPainter>
#include <QVector>
#include <QPoint>
#include <QElapsedTimer>

enum GestureType {
    GESTURE_NONE,
    GESTURE_TAP,
    GESTURE_DOUBLE_TAP,
    GESTURE_LONG_PRESS,
    GESTURE_SWIPE_LEFT,
    GESTURE_SWIPE_RIGHT,
    GESTURE_SWIPE_UP,
    GESTURE_SWIPE_DOWN,
    GESTURE_PINCH_IN,
    GESTURE_PINCH_OUT,
    GESTURE_ROTATE
};

struct GesturePoint {
    QPoint position;
    QPoint startPosition;
    QPoint previousPosition;
    qint64 timestamp;
    double velocity;
};

class GestureArea : public QWidget
{
    Q_OBJECT

public:
    explicit GestureArea(QWidget *parent = nullptr);
    ~GestureArea();

signals:
    void gestureDetected(const QString &gestureInfo);

protected:
    bool event(QEvent *event) override;
    void paintEvent(QPaintEvent *event) override;
    void mousePressEvent(QMouseEvent *event) override;
    void mouseMoveEvent(QMouseEvent *event) override;
    void mouseReleaseEvent(QMouseEvent *event) override;

private:
    void handleTouchEvent(QTouchEvent *touchEvent);
    void detectGestures();
    void drawGestureTrail(QPainter &painter);
    QString getGestureName(GestureType type) const;
    
    QVector<GesturePoint> gesturePoints;
    QVector<QPoint> trailPoints;
    GestureType currentGesture;
    QElapsedTimer tapTimer;
    bool longPressDetected;
    int tapCount;
    qint64 lastTapTime;
    
    // 手势阈值
    static const int TAP_THRESHOLD = 100;      // 点击时间阈值(ms)
    static const int LONG_PRESS_THRESHOLD = 500; // 长按时间阈值(ms)
    static const int SWIPE_THRESHOLD = 50;      // 滑动距离阈值(pixels)
    static const int DOUBLE_TAP_INTERVAL = 300; // 双击间隔(ms)
};

#endif // GESTUREAREA_H

2.10 手势区域实现 (GestureArea.cpp)

cpp 复制代码
#include "GestureArea.h"
#include <QPainter>
#include <QDebug>
#include <cmath>

GestureArea::GestureArea(QWidget *parent)
    : QWidget(parent)
{
    setAttribute(Qt::WA_AcceptTouchEvents, true);
    setAttribute(Qt::WA_StaticContents);
    
    currentGesture = GESTURE_NONE;
    longPressDetected = false;
    tapCount = 0;
    lastTapTime = 0;
    
    tapTimer.start();
    
    setStyleSheet("background-color: #ecf0f1; border: 2px solid #bdc3c7; border-radius: 10px;");
}

GestureArea::~GestureArea()
{
}

bool GestureArea::event(QEvent *event)
{
    if (event->type() == QEvent::TouchBegin ||
        event->type() == QEvent::TouchUpdate ||
        event->type() == QEvent::TouchEnd) {
        handleTouchEvent(static_cast<QTouchEvent *>(event));
        return true;
    }
    
    return QWidget::event(event);
}

void GestureArea::handleTouchEvent(QTouchEvent *touchEvent)
{
    const QList<QTouchEvent::TouchPoint> points = touchEvent->touchPoints();
    
    if (points.isEmpty()) return;
    
    // 处理第一个触摸点
    const QTouchEvent::TouchPoint &point = points.first();
    
    GesturePoint gp;
    gp.position = point.pos().toPoint();
    gp.startPosition = point.startPos().toPoint();
    gp.previousPosition = point.lastPos().toPoint();
    gp.timestamp = QDateTime::currentMSecsSinceEpoch();
    
    // 计算速度
    if (!gesturePoints.isEmpty()) {
        GesturePoint &prev = gesturePoints.last();
        double distance = QLineF(prev.position, gp.position).length();
        double timeDiff = gp.timestamp - prev.timestamp;
        gp.velocity = timeDiff > 0 ? distance / timeDiff : 0;
    }
    
    gesturePoints.append(gp);
    trailPoints.append(gp.position);
    
    // 限制轨迹点数
    if (trailPoints.size() > 100) {
        trailPoints.removeFirst();
    }
    
    // 检测手势
    detectGestures();
    
    update();
}

void GestureArea::detectGestures()
{
    if (gesturePoints.size() < 2) return;
    
    GesturePoint &start = gesturePoints.first();
    GesturePoint &end = gesturePoints.last();
    
    QLineF movement(start.position, end.position);
    double distance = movement.length();
    qint64 duration = end.timestamp - start.timestamp;
    
    // 检测点击
    if (distance < 10 && duration < TAP_THRESHOLD) {
        if (duration > LONG_PRESS_THRESHOLD && !longPressDetected) {
            currentGesture = GESTURE_LONG_PRESS;
            longPressDetected = true;
            emit gestureDetected(getGestureName(currentGesture));
        } else if (duration < TAP_THRESHOLD) {
            // 双击检测
            if (tapCount == 0) {
                tapCount = 1;
                lastTapTime = end.timestamp;
            } else if (end.timestamp - lastTapTime < DOUBLE_TAP_INTERVAL) {
                currentGesture = GESTURE_DOUBLE_TAP;
                tapCount = 0;
                emit gestureDetected(getGestureName(currentGesture));
            }
        }
    }
    
    // 检测滑动
    if (distance > SWIPE_THRESHOLD) {
        double angle = movement.angle();
        
        if (angle >= -45 && angle <= 45) {
            currentGesture = GESTURE_SWIPE_RIGHT;
        } else if (angle > 45 && angle <= 135) {
            currentGesture = GESTURE_SWIPE_DOWN;
        } else if (angle > 135 || angle <= -135) {
            currentGesture = GESTURE_SWIPE_LEFT;
        } else if (angle > -135 && angle <= -45) {
            currentGesture = GESTURE_SWIPE_UP;
        }
        
        emit gestureDetected(getGestureName(currentGesture));
    }
    
    // 检测捏合(需要多点触控)
    if (gesturePoints.size() >= 2) {
        // 简化的捏合检测
        // 实际实现需要更复杂的计算
    }
}

void GestureArea::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event);
    
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);
    
    // 绘制背景
    painter.fillRect(rect(), QColor("#ecf0f1"));
    
    // 绘制手势轨迹
    drawGestureTrail(painter);
    
    // 绘制当前手势信息
    if (currentGesture != GESTURE_NONE) {
        painter.setPen(QPen(Qt::red, 3));
        painter.setFont(QFont("Arial", 16, QFont::Bold));
        painter.drawText(rect(), Qt::AlignCenter, getGestureName(currentGesture));
    }
    
    // 绘制触摸点
    if (!gesturePoints.isEmpty()) {
        GesturePoint &gp = gesturePoints.last();
        painter.setPen(Qt::NoPen);
        painter.setBrush(QColor(52, 152, 219, 150));
        painter.drawEllipse(gp.position, 30, 30);
    }
}

void GestureArea::drawGestureTrail(QPainter &painter)
{
    if (trailPoints.size() < 2) return;
    
    painter.setPen(QPen(QColor(52, 152, 219, 100), 3, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
    
    for (int i = 1; i < trailPoints.size(); ++i) {
        painter.drawLine(trailPoints[i-1], trailPoints[i]);
    }
}

QString GestureArea::getGestureName(GestureType type) const
{
    switch (type) {
        case GESTURE_NONE: return "无手势";
        case GESTURE_TAP: return "单击";
        case GESTURE_DOUBLE_TAP: return "双击";
        case GESTURE_LONG_PRESS: return "长按";
        case GESTURE_SWIPE_LEFT: return "向左滑动";
        case GESTURE_SWIPE_RIGHT: return "向右滑动";
        case GESTURE_SWIPE_UP: return "向上滑动";
        case GESTURE_SWIPE_DOWN: return "向下滑动";
        case GESTURE_PINCH_IN: return "捏合缩小";
        case GESTURE_PINCH_OUT: return "展开放大";
        case GESTURE_ROTATE: return "旋转";
        default: return "未知手势";
    }
}

void GestureArea::mousePressEvent(QMouseEvent *event)
{
    GesturePoint gp;
    gp.position = event->pos();
    gp.startPosition = event->pos();
    gp.previousPosition = event->pos();
    gp.timestamp = QDateTime::currentMSecsSinceEpoch();
    gp.velocity = 0;
    
    gesturePoints.clear();
    gesturePoints.append(gp);
    trailPoints.clear();
    trailPoints.append(event->pos());
    
    longPressDetected = false;
    currentGesture = GESTURE_NONE;
    
    update();
}

void GestureArea::mouseMoveEvent(QMouseEvent *event)
{
    if (!gesturePoints.isEmpty()) {
        GesturePoint &last = gesturePoints.last();
        GesturePoint gp;
        gp.position = event->pos();
        gp.startPosition = last.startPosition;
        gp.previousPosition = last.position;
        gp.timestamp = QDateTime::currentMSecsSinceEpoch();
        
        double distance = QLineF(last.position, gp.position).length();
        double timeDiff = gp.timestamp - last.timestamp;
        gp.velocity = timeDiff > 0 ? distance / timeDiff : 0;
        
        gesturePoints.append(gp);
        trailPoints.append(event->pos());
        
        detectGestures();
        update();
    }
}

void GestureArea::mouseReleaseEvent(QMouseEvent *event)
{
    if (!gesturePoints.isEmpty()) {
        GesturePoint &last = gesturePoints.last();
        last.position = event->pos();
        last.timestamp = QDateTime::currentMSecsSinceEpoch();
        
        // 检测点击
        QLineF movement(last.startPosition, last.position);
        if (movement.length() < 10) {
            currentGesture = GESTURE_TAP;
            emit gestureDetected(getGestureName(currentGesture));
        }
        
        gesturePoints.clear();
        trailPoints.clear();
        update();
    }
}

2.11 资源文件 (resources.qrc)

xml 复制代码
<RCC>
    <qresource prefix="/">
        <file>images/icon.png</file>
        <file>images/home.png</file>
        <file>images/keyboard.png</file>
        <file>images/gesture.png</file>
        <file>images/settings.png</file>
        <file>images/exit.png</file>
    </qresource>
</RCC>

三、编译和运行

3.1 编译步骤

bash 复制代码
# 1. 创建构建目录
mkdir build
cd build

# 2. 运行qmake
qmake ../QtTouchScreenDemo.pro

# 3. 编译
make -j4

# 4. 运行
./QtTouchScreenDemo

3.2 在Linux触摸屏设备上运行

bash 复制代码
# 设置环境变量(如果需要)
export QT_QPA_PLATFORM=eglfs
export QT_QPA_EGLFS_PHYSICAL_WIDTH=154
export QT_QPA_EGLFS_PHYSICAL_HEIGHT=90

# 运行应用程序
./QtTouchScreenDemo -platform eglfs

3.3 在Windows上运行

bash 复制代码
# 直接运行可执行文件
QtTouchScreenDemo.exe

参考代码 qt触摸屏实例 www.youwenfan.com/contentcsv/122764.html

四、功能特点

全屏触摸界面 :专为触摸屏优化的UI设计

虚拟键盘 :完整的软键盘实现,支持Shift、Caps Lock

手势识别 :支持点击、双击、长按、滑动等手势

多点触控 :支持多点触摸检测和显示

响应式布局 :自适应不同屏幕尺寸

触摸反馈 :视觉反馈和状态提示

模块化设计:易于扩展和维护

五、使用说明

5.1 主界面

  • 点击导航栏按钮切换不同功能模块
  • 主页显示系统时间和功能卡片

5.2 虚拟键盘

  • 点击输入框自动弹出虚拟键盘
  • 支持大小写切换和特殊字符
  • 点击空白处关闭键盘

5.3 手势识别

  • 在手势区域进行各种触摸操作
  • 实时显示识别到的手势类型
  • 显示触摸轨迹和压力信息

5.4 系统设置

  • 配置触摸参数和灵敏度
  • 启用/禁用触摸反馈
  • 触摸屏校准功能

六、扩展建议

  1. 添加动画效果:使用QPropertyAnimation添加平滑过渡
  2. 集成硬件加速:使用OpenGL渲染提高性能
  3. 增加主题切换:支持深色/浅色主题
  4. 添加手势录制:记录和回放手势操作
  5. 集成语音反馈:触摸时播放语音提示
相关推荐
小短腿的代码世界1 小时前
Qt D-Bus深度解析:跨进程通信高级架构与源码实现
qt·架构·系统架构
luoyayun3615 小时前
Qt + FFmpeg 实战:音频静音段检测
qt·ffmpeg·音视频·静音段检测
小短腿的代码世界6 小时前
Qt Quick 3D场景导入与渲染架构深度解析:从USD到PBR材质的完整管线
qt·3d·架构
小短腿的代码世界6 小时前
Qt文本布局引擎深度解析:从QTextDocument排版到渲染的完整架构
开发语言·qt·架构
小短腿的代码世界6 小时前
Qt Firebase集成深度解析:移动与嵌入式云后端解决方案
开发语言·qt
Rookie Linux6 小时前
使用Qt6 QML以及第三方库FluentUI、PCapPlusPlus开发一个自定义抓包软件
网络·c++·qt·cmake·qml
郝学胜-神的一滴6 小时前
Qt 高级开发 030:QListWidget 右键菜单全解,从策略配置到精准删除的优雅实现
开发语言·c++·qt·程序人生·用户界面
ytttr8731 天前
Qt 数字键盘实现
开发语言·qt
hoiii1871 天前
Qt 实现屏幕截图功能
开发语言·qt·命令模式