Qt 無邊框窗口實現拖動與窗口控制(最小化/最大化/關閉)

在 Qt 中,使用 Qt::FramelessWindowHint 可以創建無邊框窗口,但這樣會導致窗口無法拖動,并且系統默認的標題欄按鈕(最小化、最大化、關閉)也會消失。本文將介紹如何實現無邊框窗口的鼠標拖動功能,并添加自定義最小化、最大化和關閉按鈕


1. 設置無邊框窗口

首先,在 MainWindow 的構造函數中移除默認邊框:

MainWindow::MainWindow(QWidget *parent): QMainWindow(parent)
{ui->setupUi(this);// 設置無邊框窗口setWindowFlags(Qt::FramelessWindowHint);// 連接按鈕信號(最小化、最大化/還原、關閉)connect(ui->toolButton_minimize, &QToolButton::clicked, this, &MainWindow::showMinimized);connect(ui->toolButton_maximize, &QToolButton::clicked, this, [this]() {if (this->isMaximized()) {this->showNormal();  // 如果已最大化,則還原} else {this->showMaximized();  // 否則最大化}});connect(ui->toolButton_close, &QToolButton::clicked, this, &MainWindow::close);
}

這里:

  • toolButton_minimize 是最小化按鈕
  • toolButton_maximize 是最大化/還原切換按鈕
  • toolButton_close 是關閉按鈕

2. 實現窗口拖動功能

由于無邊框窗口無法拖動,我們需要手動處理鼠標事件:

  1. MainWindow 類中添加成員變量和重寫鼠標事件
// MainWindow.h
protected:void mousePressEvent(QMouseEvent *event) override;void mouseMoveEvent(QMouseEvent *event) override;private:QPoint m_dragPosition;  // 記錄鼠標按下時的位置
  1. 實現鼠標事件
// MainWindow.cpp
void MainWindow::mousePressEvent(QMouseEvent *event)
{if (event->button() == Qt::LeftButton) {m_dragPosition = event->globalPos() - frameGeometry().topLeft();event->accept();}QMainWindow::mousePressEvent(event);
}void MainWindow::mouseMoveEvent(QMouseEvent *event)
{if (event->buttons() & Qt::LeftButton) {move(event->globalPos() - m_dragPosition);  // 移動窗口event->accept();}QMainWindow::mouseMoveEvent(event);
}
  • mousePressEvent:當鼠標左鍵按下時,記錄當前鼠標位置相對于窗口左上角的偏移量。
  • mouseMoveEvent:當鼠標左鍵按下并移動時,計算窗口新位置并移動窗口。

3. 完整代碼示例

MainWindow.h

#include <QMainWindow>
#include <QMouseEvent>namespace Ui {
class MainWindow;
}class MainWindow : public QMainWindow
{Q_OBJECTpublic:explicit MainWindow(QWidget *parent = nullptr);~MainWindow();protected:void mousePressEvent(QMouseEvent *event) override;void mouseMoveEvent(QMouseEvent *event) override;private:Ui::MainWindow *ui;QPoint m_dragPosition;
};

MainWindow.cpp

#include "MainWindow.h"
#include "ui_MainWindow.h"MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);// 設置無邊框窗口setWindowFlags(Qt::FramelessWindowHint);// 連接按鈕信號connect(ui->toolButton_minimize, &QToolButton::clicked, this, &MainWindow::showMinimized);connect(ui->toolButton_maximize, &QToolButton::clicked, this, [this]() {if (this->isMaximized()) {this->showNormal();  // 還原} else {this->showMaximized();  // 最大化}});connect(ui->toolButton_close, &QToolButton::clicked, this, &MainWindow::close);
}MainWindow::~MainWindow()
{delete ui;
}void MainWindow::mousePressEvent(QMouseEvent *event)
{if (event->button() == Qt::LeftButton) {m_dragPosition = event->globalPos() - frameGeometry().topLeft();event->accept();}QMainWindow::mousePressEvent(event);
}void MainWindow::mouseMoveEvent(QMouseEvent *event)
{if (event->buttons() & Qt::LeftButton) {move(event->globalPos() - m_dragPosition);event->accept();}QMainWindow::mouseMoveEvent(event);
}

4. 效果

  • 窗口無邊框,可以拖動。
  • 點擊最小化按鈕,窗口最小化到任務欄。
  • 點擊最大化按鈕,窗口全屏;再次點擊還原。
  • 點擊關閉按鈕,窗口關閉。

5. 進階優化

  1. 限制拖動區域
    如果只想讓窗口的某個區域(如標題欄)可拖動,可以修改 mousePressEvent

    if (event->button() == Qt::LeftButton && ui->titleBarWidget->geometry().contains(event->pos())) {m_dragPosition = event->globalPos() - frameGeometry().topLeft();event->accept();
    }
    
  2. 雙擊最大化/還原
    可以重寫 mouseDoubleClickEvent 實現雙擊標題欄最大化/還原。

  3. 窗口陰影效果
    使用 QGraphicsDropShadowEffect 讓無邊框窗口看起來更美觀。


6. 總結

通過重寫 mousePressEventmouseMoveEvent,我們可以實現無邊框窗口的拖動功能。結合自定義按鈕,可以完全替代系統默認的標題欄,打造更個性化的 UI。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/83450.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/83450.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/83450.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Linux中的System V通信標準-共享內存、消息隊列以及信號量

在Linux系統中&#xff0c;System V IPC&#xff08;Inter-Process Communication&#xff09;提供了一系列進程間通信的機制&#xff0c;包括共享內存、消息隊列和信號量。這些機制在系統中發揮了重要作用&#xff0c;幫助進程之間進行數據交換和同步。本文將詳細介紹這些機制…

postman工具使用

基本功能操作 常用斷言 定義&#xff1a;postman 斷言借助 JavaScript - js 語言編寫代碼&#xff0c;自動判斷預期結果與實際結果是否一致。&#xff08; 注意斷言 代碼寫在 Tests 的標簽中&#xff09; 斷言響應狀態碼 斷言響應體是否包含某個字符串&#xff08;Response bo…

VBA數據庫解決方案二十:Select表達式From區域Where條件Order by

《VBA數據庫解決方案》教程&#xff08;版權10090845&#xff09;是我推出的第二套教程&#xff0c;目前已經是第二版修訂了。這套教程定位于中級&#xff0c;是學完字典后的另一個專題講解。數據庫是數據處理的利器&#xff0c;教程中詳細介紹了利用ADO連接ACCDB和EXCEL的方法…

算法-集合的使用

1、set常用操作 set<int> q; //以int型為例 默認按鍵值升序 set<int,greater<int>> p; //降序排列 int x; q.insert(x); //將x插入q中 q.erase(x); //刪除q中的x元素,返回0或1,0表示set中不存在x q.clear(); //清空q q.empty(); //判斷q是否為空&a…

C++文件和流基礎

C文件和流基礎 1. C文件和流基礎1.1 文件和流的概念1.2 標準庫支持1.3 常用文件流類ifstream 類ofstream 類fstream 類 2.1 打開文件使用構造函數打開文件使用 open() 成員函數打開文件打開文件的模式標志 2.2 關閉文件使用 close() 成員函數關閉文件關閉文件的重要性 3.1 寫入…

Maven---配置本地倉庫

目錄 5. 5.1在Maven路徑下新建文件夾用于本地倉庫存儲 5.2 復制本地倉庫路徑 5.3 找到配置文件路徑&#xff0c;使用VSCode方式打開 5.4 新增一行代碼 5.5 復制本地倉庫路徑&#xff0c;設置存儲路徑 5.1在Maven路徑下新建文件夾用于本地倉庫存儲 5.2 復制本地倉庫路徑 5…

Vue3 + Element Plus + TypeScript 中 el-cascader 實現模擬用戶點擊功能

模擬點擊&#xff0c;調用 el-cascader 的公開方法 togglePopperVisible 來展開下拉框 MaterialOut.vue <script setup lang"ts" name"MaterialOut"> ...... import { ElMessage, type ElCascader } from "element-plus";// 級聯組件實例…

新能源汽車與油車銷量

中國油車與新能源車銷量對比&#xff08;2022-2025年&#xff09; ?1. 市場份額演化&#xff08;2022-2025年&#xff09;? ?年份? ?新能源車銷量 &#xff08;滲透率&#xff09;? ?燃油車銷量 &#xff08;滲透率&#xff09;? ?關鍵事件? ?2022? 688.7萬輛…

C++ list代碼練習、set基礎概念、set對象創建、set大小操作

對應力扣&#xff0c;回文鏈表&#xff0c;代碼見下 /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(nullptr) {}* ListNode(int x) : val(x), next(nullptr) {}* ListNode(int x, …

前端面試寶典---前端水印

明水印 1. 背景圖 通過css的background-image加載背景圖 2. canvasbackground水印 前端水印實現思路與示例代碼 一、核心實現思路 Canvas動態生成水印 通過Canvas繪制文本或圖案&#xff0c;將生成的圖像轉為Base64格式&#xff0c;作為背景圖重復平鋪到目標元素上。例如&…

惡意軟件清理工具,讓Mac電腦安全更簡單

?你的Mac最近是不是開始表演"電子迷惑行為"&#xff1f;瀏覽器主頁突然變成澳門賭場&#xff0c;風扇轉得比直升機螺旋槳還猛......恭喜你&#xff01;可能中獎獲得"惡意軟件大禮包"&#xff01;別慌&#xff0c;今天就教你用惡意軟件清理工具化身數字特工…

Spring Boot 3.X 下Redis緩存的嘗試(二):自動注解實現自動化緩存操作

前言 上文我們做了在Spring Boot下對Redis的基本操作&#xff0c;如果頻繁對Redis進行操作而寫對應的方法顯示使用注釋更會更高效&#xff1b; 比如&#xff1a; 依之前操作對一個業務進行定入緩存需要把數據拉取到后再定入&#xff1b; 而今天我們可以通過注釋的方式不需要額外…

Deepseek應用技巧-Dify安裝和踩坑指南

前言&#xff1a;Dify的名號是非常大的&#xff0c;作為私有化AI部署中必不可少的一個組件&#xff0c;他的功能和COZE十分相似&#xff0c;可以進行工作流和智能體的搭建&#xff0c;有非常強大的功能&#xff0c;那本節就將來揭開Dify的神秘的面紗&#xff0c;首先看一下Dify…

ubuntu24.04安裝教程(圖文詳解)

Ubuntu 24.04 LTS&#xff0c;代號 Noble Numbat&#xff0c;于 2024 年 4 月 25 日發布&#xff0c;現在可以從 Ubuntu 官方網站及其鏡像下載。此版本將在 2029 年 4 月之前接收為期五年的官方安全和維護更新。 關于 Ubuntu 24.04 LTS 的一些關鍵點&#xff1a; 發布日期&am…

數據綁定頁面的完整的原理、邏輯關系、實現路徑是什么?頁面、表格、字段、屬性、值、按鈕、事件、模型、腳本、服務編排、連接器等之間的關系又是什么?

目錄 一、核心概念:什么是數據綁定頁面? 二、涉及的組件及其邏輯關系 頁面(Page): 表格(Table): 字段(Field): 屬性(Property): 值(Value): 按鈕(Button): 事件(Event): 模型(Model): 腳本(Script): 服務(Service): 服務編排(Se…

【 SpringCloud | 微服務 網關技術 】

單體架構時我們只需要完成一次用戶登錄、身份校驗&#xff0c;就可以在所有業務中獲取到用戶信息。而微服務拆分后&#xff0c;每個微服務都獨立部署&#xff0c;這就存在一些問題&#xff1a; 每個微服務都需要編寫登錄校驗、用戶信息獲取的功能嗎&#xff1f; 當微服務之間調…

python,Dataframe基于所有包含某個關鍵字的列等于某個值過濾

在 Python 中&#xff0c;使用 Pandas 的 DataFrame 丟棄符合特定條件的行&#xff0c;條件為所有包含某個關鍵字的列中&#xff0c;等于某個值&#xff08;即所有包含某個關鍵字的列中等于某個值的行&#xff09;&#xff0c;可用以下方法實現&#xff1a; import pandas as …

50天50個小項目 (Vue3 + Tailwindcss V4) ? | Sound Board(音響控制面板)

&#x1f4c5; 我們繼續 50 個小項目挑戰&#xff01;—— SoundBoard 組件 倉庫地址&#xff1a;https://github.com/SunACong/50-vue-projects 項目預覽地址&#xff1a;https://50-vue-projects.vercel.app/ &#x1f3af; 組件目標 實現一個響應式按鈕面板&#xff0c;點…

在Ubuntu20.04上安裝ROS Noetic

本章教程,主要記錄在Ubuntu20.04上安裝ROS Noetic。 一、添加軟件源 sudo sh -c . /etc/lsb-release && echo "deb http://mirrors.tuna.tsinghua.edu.cn/ros/ubuntu/ `lsb_release -cs` main" > /etc/apt/sources.list.d/ros-latest.list二、設置秘鑰 …

神經網絡基礎:從單個神經元到多層網絡(superior哥AI系列第3期)

&#x1f9e0; 神經網絡基礎&#xff1a;從單個神經元到多層網絡&#xff08;superior哥AI系列第3期&#xff09; 哈嘍&#xff01;各位AI探索者們&#xff01;&#x1f44b; 上期我們把數學"怪獸"給馴服了&#xff0c;是不是感覺還挺輕松的&#xff1f;今天我們要進…