QGraphicsScene 管理 QGraphicsItem(單擊/選擇/移動/縮放/刪除)
簡述
在圖形檢視框架中,QGraphicsScene 提供一個快速的介面,用於管理大量 item,QGraphicsItem 是場景中 item 的基類。
圖形檢視提供了一些典型形狀的標準 item,當然,我們也可以自定義 item。除此之外,QGraphicsItem 還支援以下特性:
- 滑鼠按下、移動、釋放和雙擊事件,以及滑鼠懸浮事件、滾輪事件和上下文選單事件
- 鍵盤輸入焦點和鍵盤事件
- 拖放
- 分組:通過父子關係,或 QGraphicsItemGroup
- 碰撞檢測
下面,一起來看看 QGraphicsScene 對 QGraphicsItem 的管理,主要包括:單擊、選擇、移動、縮放、刪除等。
|
操作細節
為了實現以上功能,我們主要實現了 QGraphicsScene 和 QGraphicsItem 對應的事件,通過滑鼠和鍵盤來操作。
操作細節主要包括:
- 選擇:點選左鍵、按 Shift 鍵可以單選,按下 Ctrl 可進行多選。
- 新增:點選左鍵
- 刪除:點選右鍵,刪除滑鼠下的 item;當按下 Ctrl 選擇多個 items 時,按下 Backspace 鍵,將選中的全部刪除。
- 移動:點選左鍵,選擇 item,然後移動滑鼠;當按下 Ctrl 選擇多個 items 時,可以移動選中的 items。
- 縮放:按 Alt 鍵,然後滑鼠拖拽 item 的邊界。
在對應操作的事件中,我們輸出了一些除錯資訊,以便跟蹤。
示例
效果
原始碼
custom_item.h:
#ifndef CUSTOM_ITEM_H
#define CUSTOM_ITEM_H
#include <QGraphicsRectItem>
#include <QGraphicsScene>
//QGraphicsScene管理QGraphicsItem(單擊/選擇/移動/縮放/刪除)
// 自定義 Item
class CustomItem : public QGraphicsRectItem
{
public:
explicit CustomItem(QGraphicsItem *parent = 0 );
protected:
// Shift+左鍵:進行選擇 Alt:準備縮放
void mousePressEvent(QGraphicsSceneMouseEvent *event);
// Alt+拖拽:進行縮放 移動
void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
// 使item可使用qgraphicsitem_cast
int type() const;
private:
QPointF m_centerPointF;
bool m_bResizing;
};
// 自定義 Scene
class CustomScene : public QGraphicsScene
{
protected:
// 左鍵:新增item 右鍵:移除item
void mousePressEvent(QGraphicsSceneMouseEvent *event);
void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
// Backspace鍵移除item
void keyPressEvent(QKeyEvent *event);
};
#endif // CUSTOM_ITEM_H
custom_item.cpp:
#include <QKeyEvent>
#include <QGraphicsSceneMouseEvent>
#include <QDebug>
#include "custom_item.h"
// 自定義 Item
CustomItem::CustomItem(QGraphicsItem *parent)
: QGraphicsRectItem(parent)
{
// 畫筆 - 邊框色
QPen p = pen();
p.setWidth(2);
p.setColor(QColor(0, 160, 230));
setPen(p);
// 畫刷 - 背景色
setBrush(QColor(247, 160, 57));
// 可選擇、可移動
setFlags(QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsMovable);
}
void CustomItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
if (event->button() == Qt::LeftButton) {
if (event->modifiers() == Qt::ShiftModifier) {
qDebug() << "Custom item left clicked with shift key.";
// 選中 item
setSelected(true);
} else if (event->modifiers() == Qt::AltModifier) {
qDebug() << "Custom item left clicked with alt key.";
// 重置 item 大小
double radius = boundingRect().width() / 2.0;
QPointF topLeft = boundingRect().topLeft();
m_centerPointF = QPointF(topLeft.x() + pos().x() + radius, topLeft.y() + pos().y() + radius);
QPointF pos = event->scenePos();
qDebug() << boundingRect() << radius << this->pos() << pos << event->pos();
double dist = sqrt(pow(m_centerPointF.x()-pos.x(), 2) + pow(m_centerPointF.y()-pos.y(), 2));
if (dist / radius > 0.8) {
qDebug() << dist << radius << dist / radius;
m_bResizing = true;
} else {
m_bResizing = false;
}
} else {
qDebug() << "Custom item left clicked.";
QGraphicsItem::mousePressEvent(event);
event->accept();
}
} else if (event->button() == Qt::RightButton) {
qDebug() << "Custom item right clicked.";
event->ignore();
}
}
void CustomItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
if ((event->modifiers() == Qt::AltModifier) && m_bResizing) {
QPointF pos = event->scenePos();
double dist = sqrt(pow(m_centerPointF.x()-pos.x(), 2) + pow(m_centerPointF.y()-pos.y(), 2));
setRect(m_centerPointF.x()-this->pos().x()-dist, m_centerPointF.y()-this->pos().y()-dist, dist*2, dist*2);
} else if(event->modifiers() != Qt::AltModifier) {
qDebug() << "Custom item moved.";
QGraphicsItem::mouseMoveEvent(event);
qDebug() << "moved" << pos();
}
}
void CustomItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
if ((event->modifiers() == Qt::AltModifier) && m_bResizing) {
m_bResizing = false;
} else {
QGraphicsItem::mouseReleaseEvent(event);
}
}
int CustomItem::type() const
{
return UserType + 1;
}
// 自定義 Scene
void CustomScene::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
qDebug() << "Custom scene clicked.";
QGraphicsScene::mousePressEvent(event);
if (!event->isAccepted()) {
if (event->button() == Qt::LeftButton) {
// 在 Scene 上新增一個自定義 item
QPointF point = event->scenePos();
CustomItem *item = new CustomItem();
item->setRect(point.x()-25, point.y()-25, 60, 60);
addItem(item);
} else if (event->button() == Qt::RightButton) {
// 檢測游標下是否有 item
QGraphicsItem *itemToRemove = NULL;
foreach (QGraphicsItem *item, items(event->scenePos())) {
if (item->type() == QGraphicsItem::UserType+1) {
itemToRemove = item;
break;
}
}
// 從 Scene 上移除 item
if (itemToRemove != NULL)
removeItem(itemToRemove);
}
}
}
void CustomScene::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
qDebug() << "Custom scene moved.";
QGraphicsScene::mouseMoveEvent(event);
}
void CustomScene::keyPressEvent(QKeyEvent *event) {
if (event->key() == Qt::Key_Backspace) {
// 移除所有選中的 items
qDebug() << "selected items " << selectedItems().size();
while (!selectedItems().isEmpty()) {
removeItem(selectedItems().front());
}
} else {
QGraphicsScene::keyPressEvent(event);
}
}
使用很簡單,將 item 新增至 scene 中,通過 view 顯示即可。
#include <QApplication>
#include <QGraphicsView>
#include "custom_item.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// 建立 item
CustomItem *pItem = new CustomItem();
pItem->setRect(20, 20, 60, 60);
// 將 item 新增至場景中
CustomScene scene;
scene.setSceneRect(0, 0, 400, 300);
scene.addItem(pItem);
// 為檢視設定場景
QGraphicsView view;
view.setScene(&scene);
view.show();
return a.exec();
}
相關推薦
QGraphicsScene 管理 QGraphicsItem(單擊/選擇/移動/縮放/刪除)
簡述 在圖形檢視框架中,QGraphicsScene 提供一個快速的介面,用於管理大量 item,QGraphicsItem 是場景中 item 的基類。 圖形檢視提供了一些典型形狀的標準 item,當然,我們也可以自定義 item。除此之外,QGraphi
swift--觸摸(UITouch)事件(點擊,移動,擡起)
send nss spa bject rst sse sta location 耗時 觸摸事件: UITouch:一個手機第一次點擊屏幕,會形成一個UITouch對象,知道離開銷毀。表示觸碰。UITouch對象能表明當前手指觸碰的屏幕位置、狀態,狀態分為開始觸碰、移動、離開
vue搭建後臺管理頁面(點擊左側導航,切換右側內容)
htm right 後臺 opd imp page con com ng- home.vue頁面 <template> <div style="background-color: #EBEBEB;min-height:900px">
簡單java單例模式(單擊多次,如何讓視窗只顯示一次)
1.將實現功能的建構函式設為private 2.在寫一個public的構造方法: 如下: private static AddPerson addPerson = null; public static synchronized AddPerson GetInstance
統一認證管理系統(單點登入系統)sso 淺談
我所在的公司比較大,內部的各種管理系統和業務系統比較多,然而所有的系統都可以用公司的OA的員工工號和密碼直接進行登入 (當然登入介面都是一個就是內部OA門戶)。從進入公司以來我就一直有個問題,這是怎麼做到的?畢竟假如每個系統一套資料庫,那麼所有的系統都得同步O
做可雙擊執行的Jar包(右鍵選擇用java(TM)開啟)
例如d盤目錄下有一個資料夾包(package)名為MyPackage,包資料夾下是shutDown.java檔案。 步驟1:在d盤新建一個資料夾隨便取名為abc並將MyPackage資料夾包拖放到abc資料夾中。 步驟2:在dos中進入該abc目錄,編譯該.java檔案,命
Android 手勢識別(單擊 雙擊 擡起 短按 長按 滾動 滑動)
對於觸控式螢幕,其原生的訊息無非按下、擡起、移動這幾種,我們只需要簡單過載onTouch或者設定觸控偵聽器setOnTouchListener即可進行處理。不過,為了提高我們的APP的使用者體驗,有時候我們需要識別使用者的手勢,Android給我們提供的手勢識別工具Ge
表格變色(單擊行,把當行的單選按鈕(radio)設為選中狀態,並應用當前樣式)
需求:單擊行,自動選中當前行中的單選框按鈕。html頁面: <table id="tbList" class="table footable" data-sort="false">
Linux centos 跳過管理員密碼進行登錄(單用戶模式、救援模式)
remount 無法 linu 單用戶 blog int 成功 程序 bios 這裏列舉了兩種更改或者取消管理員密碼登錄Linux系統的方法,其實兩種方法類似,都是想方設法跳過用戶認定,直接更改用戶文件、更改密碼的過程。 為了跳過系統正常啟動過程中的某些步驟,必須知
數據庫:MySQL(單表的表記錄的操作)(二)
基礎上 des 別名 order by data database values 生成 結果 一、表記錄的增刪改查 1、增加表記錄 <1>插入一條記錄: insert [into] tab_name (field1,filed2,.......) val
排序算法(冒泡,選擇,插入,快速)查找算法(二分,快速)
元素 快速查找 冒泡排序 比較 簡單 目標 記錄 rec 向下取整 四種排序算法 1.冒泡排序 思路分析:從前往後相鄰的兩個數一次進行比較,大的往下沈,小的網上 冒。當相鄰的兩個數的比較後發現他們的排序與排序要求相反,就互
js遞歸渲染子節點(點擊父節點展示子節點)
ner container com 循環 cnblogs each ber 獲取 r+ 需求概況如下:點擊某個文件夾,顯示該文件夾下的子文件夾。文件夾的層級和數量不固定。 在這裏,我簡單準備了一下數據結構,來模擬這個效果:var nodes=[ {
設計模式:對象生成(單例、工廠、抽象工廠)
添加 對象實例 log return ray 靜態 學習 線程 tco 對象的創建有時會成為面向對象設計的一個薄弱環節。我們可以使用多種面向對象設計方案來增加對象的創建的靈活性。 單例模式:生成一個且只生成一個對象實例的特殊類 工廠方法模式:構建創建者類的繼承層級
Android系統下用js自定義gesture事件(仿ios實現移動端事件一致)
initial path acc mtab uil 查看 sans fault default 一、手勢事件 下面二維碼是一個實例dome,可掃碼直接查看: 在ios系統中,系統自帶了gesture事件,兩個手指操作的時候,就會產生一下三種手勢
python文件封裝成*.exe文件(單文件和多文件)
-- 黑板 workday 程序包 代碼 拷貝 4.5 hole nic 環境:win10 64位 python3.7 單*.py文件打包Python GUI:程序打包為exe 一、安裝Pyinstaller,命令pip install Pyinstaller,(大
kuangbin專題七 HDU1754 I Hate It (單點修改維護最大值)
cond color include 專題 一次 span 修改 信息 \n 很多學校流行一種比較的習慣。老師們很喜歡詢問,從某某到某某當中,分數最高的是多少。 這讓很多學生很反感。 不管你喜不喜歡,現在需要你做的是,就是按照老師的要求,寫一個程序,模擬老師的
訊息佇列:Ubuntu16.04安裝和Web頁面管理RabbitMQ(樓主親測、真實有效)
RabbitMQ 總來來說,RabbitMQ的安裝還是有一些難度的。不同的方式,安裝的方法也是完全不一樣,還要解決蠻多依賴。加上現在有些網站,極其不負責,很多博文都沒有經過測試檢驗就直接發出來的。樓主來親測一下,希望能對大家有好的幫助。 一、安裝前的準備 要確保,你有Erla
學生消費記錄管理系統(C語言 結構體, 連結串列)
自己在寒假練手的小專案 本系統要實現的功能: 1. 消費記錄存在檔案fee.txt中, 每一條記錄包括一個消費的交易日期、入賬日期、交易額、交易後餘額 2. (1)使用者能夠查詢自己
自定義ImageView: 實現自由縮放 ,自由移動縮放後的圖片 .雙擊放大與縮小圖片 相容ViewPager
直接擼程式碼, 複製就能用 package com.zhf.baselibrary.view; import android.annotation.SuppressLint; import android.content.Context; import android.graphi