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. 集成语音反馈:触摸时播放语音提示
相关推荐
用户805533698033 天前
不止三件套:QObject 属性系统全关键字与运行时反射!
c++·qt
xcyxiner3 天前
DicomViewer (vcpkg Windows和ubuntu编译)7
qt
Quz8 天前
QML Hello World 入门示例
qt
xcyxiner11 天前
DicomViewer (dcmtk读取dcm文件)5
qt
xcyxiner12 天前
DicomViewer (后台线程处理文件)4
qt
xcyxiner12 天前
DicomViewer (添加模型类)3
qt
xcyxiner13 天前
DicomViewer (目录调整) 2
qt
xcyxiner13 天前
dcmtk vtk vtk-dicom(gdcm) 编译(debug) v2
qt
桥田智能15 天前
桥田智能 QT-650S:面向白车身焊装的 800kg 重载快换解决方案
开发语言·qt·系统架构
森G15 天前
75、服务器源码解析---------云视频服务项目
linux·服务器·网络·c++·qt