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 系统设置
- 配置触摸参数和灵敏度
- 启用/禁用触摸反馈
- 触摸屏校准功能
六、扩展建议
- 添加动画效果:使用QPropertyAnimation添加平滑过渡
- 集成硬件加速:使用OpenGL渲染提高性能
- 增加主题切换:支持深色/浅色主题
- 添加手势录制:记录和回放手势操作
- 集成语音反馈:触摸时播放语音提示