Add minimal Qt desktop pet window

This commit is contained in:
2026-05-28 10:21:32 +08:00
parent 6ecb3ac494
commit 98d056c78d
6 changed files with 242 additions and 0 deletions
+25
View File
@@ -0,0 +1,25 @@
build/
cmake-build-*/
.vs/
.vscode/
*.user
*.suo
*.VC.db
*.VC.VC.opendb
*.autosave
# Build outputs
*.exe
*.dll
*.pdb
*.ilk
*.obj
*.o
*.a
*.lib
# Runtime/config files generated during development
config/
logs/
*.broken.json
+33
View File
@@ -0,0 +1,33 @@
cmake_minimum_required(VERSION 3.20)
project(QtDesktopPet VERSION 0.1.0 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_AUTOMOC OFF)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
find_package(Qt6 REQUIRED COMPONENTS Widgets)
qt_add_executable(QtDesktopPet
main.cpp
src/ui/PetWindow.h
src/ui/PetWindow.cpp
)
target_compile_definitions(QtDesktopPet
PRIVATE
PET_SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}"
)
target_link_libraries(QtDesktopPet
PRIVATE
Qt6::Widgets
)
if (WIN32)
target_compile_definitions(QtDesktopPet PRIVATE WIN32_LEAN_AND_MEAN NOMINMAX)
endif()
+16
View File
@@ -0,0 +1,16 @@
#include <QApplication>
#include "src/ui/PetWindow.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QApplication::setApplicationName("QtDesktopPet");
QApplication::setOrganizationName("QtDesktopPet");
PetWindow window;
window.show();
return app.exec();
}
+1
View File
@@ -0,0 +1 @@
+141
View File
@@ -0,0 +1,141 @@
#include "PetWindow.h"
#include <QAction>
#include <QContextMenuEvent>
#include <QCursor>
#include <QFileInfo>
#include <QGuiApplication>
#include <QMenu>
#include <QMouseEvent>
#include <QPixmap>
#include <QScreen>
#include <QVBoxLayout>
namespace
{
QString previewImagePath()
{
return QStringLiteral(PET_SOURCE_DIR) + QStringLiteral("/shiroko/preview.png");
}
}
PetWindow::PetWindow(QWidget *parent)
: QWidget(parent)
, m_imageLabel(new QLabel(this))
, m_dragging(false)
, m_alwaysOnTop(true)
{
setAttribute(Qt::WA_TranslucentBackground);
setWindowFlags(Qt::FramelessWindowHint | Qt::Tool | Qt::WindowStaysOnTopHint);
setMouseTracking(true);
m_imageLabel->setAlignment(Qt::AlignCenter);
m_imageLabel->setAttribute(Qt::WA_TranslucentBackground);
auto *layout = new QVBoxLayout(this);
layout->setContentsMargins(0, 0, 0, 0);
layout->addWidget(m_imageLabel);
loadPreviewImage();
}
void PetWindow::contextMenuEvent(QContextMenuEvent *event)
{
QMenu menu(this);
QAction *topAction = menu.addAction(QStringLiteral("取消置顶"));
topAction->setCheckable(true);
topAction->setChecked(m_alwaysOnTop);
menu.addSeparator();
QAction *exitAction = menu.addAction(QStringLiteral("退出"));
QAction *selectedAction = menu.exec(event->globalPos());
if (selectedAction == topAction)
{
setAlwaysOnTop(!m_alwaysOnTop);
}
else if (selectedAction == exitAction)
{
close();
}
}
void PetWindow::mouseMoveEvent(QMouseEvent *event)
{
if (m_dragging && (event->buttons() & Qt::LeftButton))
{
move(event->globalPosition().toPoint() - m_dragOffset);
event->accept();
return;
}
QWidget::mouseMoveEvent(event);
}
void PetWindow::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton)
{
m_dragging = true;
m_dragOffset = event->globalPosition().toPoint() - frameGeometry().topLeft();
event->accept();
return;
}
QWidget::mousePressEvent(event);
}
void PetWindow::mouseReleaseEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton)
{
m_dragging = false;
event->accept();
return;
}
QWidget::mouseReleaseEvent(event);
}
void PetWindow::loadPreviewImage()
{
const QString imagePath = previewImagePath();
QPixmap pixmap(imagePath);
if (pixmap.isNull())
{
m_imageLabel->setText(QStringLiteral("QtDesktopPet"));
resize(240, 160);
return;
}
const QSize targetSize(320, 320);
const QPixmap scaled = pixmap.scaled(targetSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
m_imageLabel->setPixmap(scaled);
resize(scaled.size());
if (const QScreen *screen = QGuiApplication::primaryScreen())
{
const QRect available = screen->availableGeometry();
move(available.center() - rect().center());
}
}
void PetWindow::setAlwaysOnTop(bool enabled)
{
m_alwaysOnTop = enabled;
Qt::WindowFlags flags = windowFlags();
if (enabled)
{
flags |= Qt::WindowStaysOnTopHint;
}
else
{
flags &= ~Qt::WindowStaysOnTopHint;
}
setWindowFlags(flags);
show();
}
+26
View File
@@ -0,0 +1,26 @@
#pragma once
#include <QLabel>
#include <QPoint>
#include <QWidget>
class PetWindow : public QWidget
{
public:
explicit PetWindow(QWidget *parent = nullptr);
protected:
void contextMenuEvent(QContextMenuEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override;
private:
void loadPreviewImage();
void setAlwaysOnTop(bool enabled);
QLabel *m_imageLabel;
QPoint m_dragOffset;
bool m_dragging;
bool m_alwaysOnTop;
};