refactor: new start

This commit is contained in:
ivaquero
2026-04-18 01:46:43 +08:00
parent 35e8a21f00
commit b3ecb2708a
12 changed files with 587 additions and 216 deletions
+26 -48
View File
@@ -1,60 +1,38 @@
cmake_minimum_required(VERSION 3.7...3.21)
if(${CMAKE_VERSION} VERSION_LESS 3.12)
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
endif()
project(FloatingClock)
cmake_minimum_required(VERSION 3.16)
project(flock)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 17 CACHE STRING "v")
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# Find Qt6
find_package(Qt6 REQUIRED COMPONENTS Core Widgets)
# Homebrew Qt6 路径 (自动检测或手动设置)
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
# 检测架构
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64")
set(QT6_PATH "/opt/homebrew/opt/qt" CACHE PATH "Qt6 installation path")
else()
set(QT6_PATH "/usr/local/opt/qt" CACHE PATH "Qt6 installation path")
endif()
# Set up Qt6
qt6_standard_project_setup()
# 添加到 CMake 搜索路径
list(APPEND CMAKE_PREFIX_PATH "${QT6_PATH}/lib/cmake")
endif()
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets Xml)
add_executable(${CMAKE_PROJECT_NAME} WIN32 MACOSX_BUNDLE main.cpp)
set_target_properties(${CMAKE_PROJECT_NAME} PROPERTIES
WIN32_EXECUTABLE TRUE
MACOSX_BUNDLE TRUE
# Sources
set(SOURCES
main.cpp
clockwidget.cpp
)
target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE Qt6::Core
Qt6::Gui
set(HEADERS
clockwidget.h
)
# Create executable
qt6_add_executable(flock
${SOURCES}
${HEADERS}
)
# Link Qt libraries
target_link_libraries(flock
Qt6::Core
Qt6::Widgets
Qt6::Xml
)
# macOS 特定设置
if(APPLE)
set_target_properties(FloatingClock PROPERTIES
MACOSX_BUNDLE TRUE
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/Info.plist.in
# Set up install
install(TARGETS flock
RUNTIME DESTINATION bin
)
# 修复运行时库路径
set_target_properties(FloatingClock PROPERTIES
INSTALL_RPATH "${QT6_PATH}/lib"
BUILD_WITH_INSTALL_RPATH TRUE
)
endif()
-78
View File
@@ -1,78 +0,0 @@
#ifndef FLOATINGCLOCK_H
#define FLOATINGCLOCK_H
#include <QObject>
#include <QPoint>
#include <QString>
#include <QMap>
#include <QTimer>
#include <QColor>
#include <QMouseEvent>
#include <QPaintEvent>
#include <QContextMenuEvent>
#include <QWidget>
#include <QLabel>
#include <QMenu>
#include <QAction>
class FloatingClock : public QWidget
{
Q_OBJECT
public:
explicit FloatingClock(QWidget *parent = nullptr);
~FloatingClock();
protected:
void mousePressEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override;
void paintEvent(QPaintEvent *) override;
private slots:
void updateTime();
void changeFontSize();
void changeFontColor();
void changeBgColor();
void resetSettings();
void quitApp();
private:
void showContextMenu(const QPoint &pos);
void updateStyle();
void moveToCenter();
void loadXmlConfig();
void createDefaultXml(const QString &path);
void setDefaultValues();
void applyXmlValues(const QMap<QString, QString> &values);
bool parseBool(const QString &str);
void loadUserSettings();
void saveUserSettings();
QColor parseColor(const QString &str);
QLabel *timeLabel;
int windowWidth, windowHeight;
int windowPosX, windowPosY;
int borderRadius;
int borderWidth;
QColor borderColor;
int fontSize;
QString fontFamily;
bool fontWeight;
bool fontItalic;
QColor fontColor;
QColor bgColor;
QString timeFormat;
int shadowBlurRadius;
int shadowOffsetX, shadowOffsetY;
QColor shadowColor;
bool dragging = false;
QPoint dragPos;
};
#endif
-26
View File
@@ -1,26 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleExecutable</key>
<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>com.example.FloatingClock</string>
<key>CFBundleName</key>
<string>FloatingClock</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>LSMinimumSystemVersion</key>
<string>10.12</string>
<key>NSHighResolutionCapable</key>
<true/>
</dict>
</plist>
+123
View File
@@ -0,0 +1,123 @@
# QFlock - Qt6 浮动时钟
## 功能特性
**已实现的功能:**
- **无边框窗口** - 简洁的浮动时钟界面
- **拖拽移动** - 鼠标左键拖拽移动窗口位置
- **右键菜单** - 丰富的自定义选项
- **总在最前** - 始终显示在其他窗口之上
- **透明背景** - 支持半透明背景效果
- **自定义样式** - 可调整字体颜色、背景颜色、字体大小
- **设置持久化** - 自动保存和恢复用户设置
- **跨平台支持** - 基于Qt6,支持macOS/Linux/Windows
## 使用方法
### 基本操作
- **移动时钟**:鼠标左键点击并拖拽
- **显示菜单**:右键点击时钟
- **退出应用**:右键菜单选择"退出"
### 自定义设置
- **字体颜色**:右键菜单 → 设置字体颜色
- **背景颜色**:右键菜单 → 设置背景颜色
- **字体大小**:右键菜单 → 设置字体大小
- **总在最前**:右键菜单 → 勾选/取消"总在最前"
- **重置设置**:右键菜单 → 重置设置
### 构建和运行
#### 快速构建(推荐):
```bash
# 一键构建
./build.sh
# 运行应用
./build/flock.app/Contents/MacOS/flock # macOS
./build/flock # Linux
```
#### 手动构建:
```bash
# 清理旧的构建文件
./clean.sh
# 生成Makefile
qmake flock.pro
# 编译
make
# 运行
./build/flock.app/Contents/MacOS/flock # macOS
./build/flock # Linux
```
#### 使用CMake构建:
```bash
mkdir build && cd build
cmake ..
make
./flock
```
### 项目结构
```text
qflock/
├── build/ # 构建输出目录
│ ├── flock.app/ # macOS应用包
│ ├── *.o # 目标文件
│ ├── moc_*.cpp # Qt元对象编译器输出
│ └── Makefile # 构建文件
├── src/ # 源代码(建议)
├── build.sh # 一键构建脚本
├── clean.sh # 清理脚本
├── flock.pro # qmake项目文件
├── CMakeLists.txt # CMake项目文件
└── README.md
```
## 技术特点
- **Qt6框架**:使用最新的Qt6库
- **透明窗口**:支持RGBA透明背景
- **定时器更新**:每秒更新时钟显示
- **设置管理**:使用QSettings持久化用户偏好
- **事件处理**:自定义鼠标事件实现拖拽功能
## 开发说明
### 构建输出管理
- 所有编译生成的文件(.o, moc_*.cpp, Makefile等)都会输出到`build/`目录
- 可执行文件位于`build/flock.app/Contents/MacOS/flock`macOS)或`build/flock`Linux
- 使用`./clean.sh`可以快速清理所有构建文件
- 使用`./build.sh`可以进行完整的一键构建
### 自定义构建配置
可以在`flock.pro`中修改以下配置:
- `DESTDIR`:可执行文件输出目录
- `OBJECTS_DIR`:目标文件输出目录
- `MOC_DIR`:元对象编译器输出目录
## 更新日志
### v1.0.0 (2026-04-18)
- ✨ 初始版本发布
- ✨ 基础时钟功能
- ✨ 拖拽移动支持
- ✨ 右键菜单功能
- ✨ 样式自定义
- ✨ 设置持久化
- ✨ 构建输出目录管理
+97 -17
View File
@@ -1,9 +1,9 @@
# ⏰ Floating Clock
# ⏰ Flock
![code size](https://img.shields.io/github/languages/code-size/ivaquero/floating-clock.svg)
![repo size](https://img.shields.io/github/repo-size/ivaquero/floating-clock.svg)
This project aims to build a cross-platform floating clock based on PySide6 & Qt6.
This project aims to build a cross-platform floating clock based on Qt6.
## Motivation
@@ -12,28 +12,108 @@ When on macOS / Linux, the clock on the menu bar is too small to be noticeable,
![clock](doc/clock.png)
## Roadmap
## ✨ Features
- [ ] Main Window
- [x] Frameless
- [ ] **Main Window**
- [ ] Frameless
- [x] Drag and Move
- [x] Right Click Menu
- [x] Always On Top
- [ ] Always On Top
- [ ] Show in Fullscreen Mode
- [x] Font
- [x] Set Color
- [x] **Style**
- [x] Set Background Color
- [x] Change Size
- [x] Configuratin File
- [x] Read Settings
- [x] Write Settings
- [x] Reset Settings
- [ ] Time
- [x] Set Font Color
- [x] Set FontSize
- [ ] **Configuration File** (XML)
- [ ] Read Settings
- [ ] Write Settings
- [ ] Reset Settings
- [ ] **Time**
- [ ] Select Time Zone
- [ ] Set Alarms
## For Testing
## Quick Start
```python
python -m pip install -r requirements.txt
### Build and Run
#### Quick Build (Recommended)
```bash
# One-click build
./build.sh
# Run application
./build/flock.app/Contents/MacOS/flock # macOS
./build/flock # Linux
```
#### Manual Build
```bash
# Clean build files
./clean.sh
# Generate Makefile
qmake flock.pro
# Build
make
# Run
./build/flock.app/Contents/MacOS/flock # macOS
./build/flock # Linux
```
#### Using CMake
```bash
mkdir build && cd build
cmake ..
make
./flock
```
### Usage
- **Move**: Left-click and drag
- **Menu**: Right-click for context menu
- **Customize**: Change colors, font size, always-on-top behavior
### Project Structure
```text
qflock/
├── build/ # Build output directory
│ ├── flock.app/ # macOS application bundle
│ ├── *.o # Object files
│ ├── moc_*.cpp # Qt meta-object compiler output
│ └── Makefile # Build file
├── build.sh # One-click build script
├── clean.sh # Clean script
├── flock.pro # qmake project file
├── CMakeLists.txt # CMake project file
└── README.md
```
### Build Output Management
- All compilation files (.o, moc_*.cpp, Makefile, etc.) are output to `build/` directory
- Executable files are located at `build/flock.app/Contents/MacOS/flock` (macOS) or `build/flock` (Linux)
- Use `./clean.sh` to quickly clean all build files
- Use `./build.sh` for complete one-click build
### Next Steps
- Time zone selection
- Alarm functionality
- Enhanced UI/UX
## Requirements
- Qt6 (Core, Widgets)
- C++17 compatible compiler
- CMake 3.16+ (optional, for CMake build)
## License
See LICENSE file for details.
Executable
+30
View File
@@ -0,0 +1,30 @@
#!/bin/bash
# Build script
echo "Starting QFlock build..."
# Create build directory if it doesn't exist
mkdir -p build
# Clean old build files
echo "Cleaning old build files..."
rm -rf build/*
# Generate Makefile using qmake
echo "Generating Makefile..."
qmake flock.pro
# Build project
echo "Starting compilation..."
make
# Check build result
if [ -f "build/flock.app/Contents/MacOS/flock" ] || [ -f "build/flock" ]; then
echo "Build successful!"
echo "Executable location:"
[ -f "build/flock.app/Contents/MacOS/flock" ] && echo " - build/flock.app/Contents/MacOS/flock (macOS)"
[ -f "build/flock" ] && echo " - build/flock (Linux)"
else
echo "Build failed!"
exit 1
fi
Executable
+18
View File
@@ -0,0 +1,18 @@
#!/bin/bash
# Clean build files script
echo "Cleaning build files..."
# Delete files in build directory
if [ -d "build" ]; then
rm -rf build/*
echo "Build directory cleaned"
fi
# Delete .app bundle
if [ -d "flock.app" ]; then
rm -rf flock.app
echo "flock.app deleted"
fi
echo "Cleanup complete!"
+214
View File
@@ -0,0 +1,214 @@
#include "clockwidget.h"
#include <QVBoxLayout>
#include <QTime>
#include <QColorDialog>
#include <QFontDialog>
#include <QInputDialog>
#include <QMessageBox>
ClockWidget::ClockWidget(QWidget *parent)
: QWidget(parent), m_dragging(false)
{
setupUI();
createMenu();
loadSettings();
// Set window properties
setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::Tool);
setAttribute(Qt::WA_TranslucentBackground);
setFixedSize(200, 80);
// Start timer
m_timer = new QTimer(this);
connect(m_timer, &QTimer::timeout, this, &ClockWidget::updateTime);
m_timer->start(1000);
updateTime();
}
ClockWidget::~ClockWidget()
{
saveSettings();
}
void ClockWidget::setupUI()
{
m_timeLabel = new QLabel(this);
m_timeLabel->setAlignment(Qt::AlignCenter);
QVBoxLayout *layout = new QVBoxLayout(this);
layout->addWidget(m_timeLabel);
layout->setContentsMargins(10, 10, 10, 10);
}
void ClockWidget::createMenu()
{
m_contextMenu = new QMenu(this);
QAction *alwaysOnTopAction = new QAction("Always on Top", this);
alwaysOnTopAction->setCheckable(true);
alwaysOnTopAction->setChecked(true);
connect(alwaysOnTopAction, &QAction::triggered, this, &ClockWidget::toggleAlwaysOnTop);
QAction *fontColorAction = new QAction("Set Font Color", this);
connect(fontColorAction, &QAction::triggered, this, &ClockWidget::changeFontColor);
QAction *bgColorAction = new QAction("Set Background Color", this);
connect(bgColorAction, &QAction::triggered, this, &ClockWidget::changeBackgroundColor);
QAction *fontSizeAction = new QAction("Set Font Size", this);
connect(fontSizeAction, &QAction::triggered, this, &ClockWidget::changeFontSize);
QAction *resetAction = new QAction("Reset Settings", this);
connect(resetAction, &QAction::triggered, this, &ClockWidget::resetSettings);
QAction *quitAction = new QAction("Quit", this);
connect(quitAction, &QAction::triggered, this, &ClockWidget::quitApplication);
m_contextMenu->addAction(alwaysOnTopAction);
m_contextMenu->addSeparator();
m_contextMenu->addAction(fontColorAction);
m_contextMenu->addAction(bgColorAction);
m_contextMenu->addAction(fontSizeAction);
m_contextMenu->addSeparator();
m_contextMenu->addAction(resetAction);
m_contextMenu->addAction(quitAction);
}
void ClockWidget::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton)
{
m_dragging = true;
m_dragPosition = event->globalPosition().toPoint() - frameGeometry().topLeft();
event->accept();
}
}
void ClockWidget::mouseMoveEvent(QMouseEvent *event)
{
if (m_dragging && (event->buttons() & Qt::LeftButton))
{
move(event->globalPosition().toPoint() - m_dragPosition);
event->accept();
}
}
void ClockWidget::contextMenuEvent(QContextMenuEvent *event)
{
m_contextMenu->exec(event->globalPos());
}
void ClockWidget::updateTime()
{
QString currentTime = QTime::currentTime().toString("HH:mm:ss");
m_timeLabel->setText(currentTime);
}
void ClockWidget::toggleAlwaysOnTop()
{
m_alwaysOnTop = !m_alwaysOnTop;
Qt::WindowFlags flags = windowFlags();
if (m_alwaysOnTop)
{
flags |= Qt::WindowStaysOnTopHint;
}
else
{
flags &= ~Qt::WindowStaysOnTopHint;
}
setWindowFlags(flags);
show();
}
void ClockWidget::changeFontColor()
{
QColor color = QColorDialog::getColor(m_fontColor, this, "Choose Font Color");
if (color.isValid())
{
m_fontColor = color;
updateStyleSheet();
}
}
void ClockWidget::changeBackgroundColor()
{
QColor color = QColorDialog::getColor(m_backgroundColor, this, "Choose Background Color");
if (color.isValid())
{
m_backgroundColor = color;
updateStyleSheet();
}
}
void ClockWidget::changeFontSize()
{
bool ok;
int size = QInputDialog::getInt(this, "Set Font Size", "Font Size:", m_fontSize, 8, 72, 1, &ok);
if (ok)
{
m_fontSize = size;
updateStyleSheet();
}
}
void ClockWidget::resetSettings()
{
int ret = QMessageBox::question(this, "Reset Settings", "Are you sure you want to reset all settings?");
if (ret == QMessageBox::Yes)
{
m_settings->clear();
loadSettings();
updateStyleSheet();
}
}
void ClockWidget::quitApplication()
{
qApp->quit();
}
void ClockWidget::loadSettings()
{
m_settings = new QSettings("QFlock", "Clock", this);
m_fontColor = m_settings->value("fontColor", QColor(255, 255, 255)).value<QColor>();
m_backgroundColor = m_settings->value("backgroundColor", QColor(0, 0, 0, 150)).value<QColor>();
m_fontSize = m_settings->value("fontSize", 24).toInt();
m_alwaysOnTop = m_settings->value("alwaysOnTop", true).toBool();
// Restore window position
QPoint pos = m_settings->value("position", QPoint(100, 100)).toPoint();
move(pos);
updateStyleSheet();
}
void ClockWidget::saveSettings()
{
m_settings->setValue("fontColor", m_fontColor);
m_settings->setValue("backgroundColor", m_backgroundColor);
m_settings->setValue("fontSize", m_fontSize);
m_settings->setValue("alwaysOnTop", m_alwaysOnTop);
m_settings->setValue("position", pos());
}
void ClockWidget::updateStyleSheet()
{
QString styleSheet = QString(
"QLabel { "
"color: %1; "
"font-size: %2pt; "
"font-weight: bold; "
"background-color: %3; "
"border-radius: 10px; "
"padding: 5px; "
"}")
.arg(m_fontColor.name(),
QString::number(m_fontSize),
m_backgroundColor.name(QColor::HexArgb));
m_timeLabel->setStyleSheet(styleSheet);
setStyleSheet(QString("background-color: transparent;"));
}
+59
View File
@@ -0,0 +1,59 @@
#ifndef CLOCKWIDGET_H
#define CLOCKWIDGET_H
#include <QWidget>
#include <QLabel>
#include <QTimer>
#include <QMouseEvent>
#include <QMenu>
#include <QAction>
#include <QSettings>
#include <QFont>
#include <QColor>
class ClockWidget : public QWidget
{
Q_OBJECT
public:
explicit ClockWidget(QWidget *parent = nullptr);
~ClockWidget();
protected:
void mousePressEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
void contextMenuEvent(QContextMenuEvent *event) override;
private slots:
void updateTime();
void toggleAlwaysOnTop();
void changeFontColor();
void changeBackgroundColor();
void changeFontSize();
void resetSettings();
void quitApplication();
private:
void setupUI();
void createMenu();
void loadSettings();
void saveSettings();
void updateStyleSheet();
QLabel *m_timeLabel;
QTimer *m_timer;
QMenu *m_contextMenu;
// Drag related
QPoint m_dragPosition;
bool m_dragging;
// Settings
QSettings *m_settings;
QColor m_fontColor;
QColor m_backgroundColor;
int m_fontSize;
bool m_alwaysOnTop;
};
#endif // CLOCKWIDGET_H
-41
View File
@@ -1,41 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- 浮动时钟配置文件 -->
<ClockConfig>
<!-- 窗口设置 -->
<Window>
<Width>350</Width>
<Height>180</Height>
<PosX>-1</PosX> <!-- -1表示屏幕居中 -->
<PosY>-1</PosY>
<BorderRadius>20</BorderRadius>
<BorderWidth>2</BorderWidth>
<BorderColor>#333333</BorderColor>
</Window>
<!-- 字体设置 -->
<Font>
<Size>96</Size>
<Family>Arial</Family>
<Bold>true</Bold>
<Italic>false</Italic>
<Color>#ff6600</Color>
</Font>
<!-- 背景设置 -->
<Background>
<Color>#1a000000</Color> <!-- 半透明黑色背景 -->
</Background>
<!-- 时间格式 -->
<Time>
<Format>HH:mm:ss</Format>
</Time>
<!-- 阴影效果 -->
<Shadow>
<BlurRadius>30</BlurRadius>
<OffsetX>4</OffsetX>
<OffsetY>4</OffsetY>
<Color>#80000000</Color>
</Shadow>
</ClockConfig>
+13 -3
View File
@@ -1,15 +1,25 @@
# Created by and for Qt Creator This file was created for editing the project sources only.
# You may attempt to use it for building too, by modifying this file here.
#TARGET = flock
TARGET = flock
QT = core gui widgets
SOURCES = \
$$PWD/main.cpp
$$PWD/main.cpp \
$$PWD/clockwidget.cpp
HEADERS = \
$$PWD/clockwidget.h
INCLUDEPATH = \
$$PWD/.
#DEFINES =
# Set build output directories
DESTDIR = $$PWD/build
OBJECTS_DIR = $$PWD/build
MOC_DIR = $$PWD/build
RCC_DIR = $$PWD/build
UI_DIR = $$PWD/build
#DEFINES =
+6 -2
View File
@@ -1,11 +1,15 @@
#include <QApplication>
#include "FloatingClock.h"
#include "clockwidget.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
FloatingClock clock;
app.setApplicationName("QFlock");
app.setOrganizationName("QFlock");
app.setApplicationDisplayName("QFlock");
ClockWidget clock;
clock.show();
return app.exec();