اولویت رویداد ماوس
-
p{direction:rtl; text-align:right;font-family:tahoma}. سلام
من یک Widget ساختم که رویداد paintEvent اون یک جدول رسم میکنه. میخوام هروقت ماوس روی هرکدوم از سلول های جدول رفت اون سلول به نوعی Highlight بشه.p{direction:rtl; text-align:right;font-family:tahoma}. برای اینکه تشخیص بدم نقطه ای که ماوس هست روی سلول چندم قرار میگیره مشکلی ندارم و با یک تقسیم ساده انجامش دادم.
اما مهم ترسیم اون Highlight هست! اولین بار در رویداد paintEvent بعد از کد ترسیم جدول کدی نوشتم که بر اساس مختصات ماوس یک مستطیل روی اون محدوده ترسیم کنه و رویداد mouseMoveEvent هم update رو انجام میداد و کاملا هم درست کار میکرد اما متوجه شدم که زمانی که ماوس رو روی جدول حرکت میدم کارکرد CPU به بیش از 50 درصد میرسه! که این بدلیل update شدن ویجت در هر حرکت ماوس هست! پس روش درستی نیست.p{direction:rtl; text-align:right;font-family:tahoma}. دنبال راهی برای داشتن یک مستطیل بودم که با استفاده از دستور move قابلیت جابجایی داشته باشه. پس یک ویجت نوشتم که یک مستطیل در خودش رسم میکنه و اون رو در ویجت جدول قرار دادم و کد move رو نوشتم.
اما باز هم یک مشکل وجود داره! من برای حرکت دادن ویجت مستطیل به رویداد mouseMoveEvent ویجت جدول نیاز دارم و وقتی مستطیل روی جدول هست رویداد ماوس به ویجت جلوتر یعنی مستطیل ارسال میشه!p{direction:rtl; text-align:right;font-family:tahoma}. چطوره از eventFilter برای انتقال رویداد از مستطیل به جدول استفاده کنم؟ البته اگر این تنها راهه؟
نمیشه کاری کرد که ویجت مستطیل تاثیری در دریافت رویداد نداشته باشه؟ -
p{direction:rtl;text-align:right}. اینطوری بدون دیدن کد که نمیشه نظری داد.
فقط خواستم یک نکته رو بگم اینکه شما اگر 1000 بار پشت سر هم update کنی مشکلی نیست به شرطی که تمام عملیات رو paintEvent انجام بده و شما از متد های دیگه (مثلا mouseMoveEvent) فقط ()update رو صدا کنی نه اینکه توی اون رویداد هم پردازش گرافیکی انجام بدی.
paintEvent مستقیما با gpu ارتباط برقرار میکنه (توسط سیستم عامل) و سنگینی پردازش رو دوش cpu نیست. -
p{direction:rtl; text-align:right;font-family:tahoma}. کد من هم دقیقا همین شرایط رو داره. رویداد paintEvent یک سری جدول و اعداد داخلشون رو رسم میکنه. در حالت های مختلف تست کردم CPU Usage حداقل به 30% میرسه! اصلا این راه درستی نیست که برای ترسیم یک مستطیل کوچک کل ویحت دوباره ترسیم بشه.
اگر ویجت جلویی یعنی مستطیل رویداد حرکت ماوس رو خودش نمیگرفت و میداد به جدول پشتش درست میشد.p{direction:rtl; text-align:right;font-family:tahoma}. استفاده چندین ویجت درون همدیگه از نظر کارایی برنامه مشکلی ایجاد میکنه؟ میتونم جدول و مستطیل رو داخل یک ویجت دیگه قرار بدم و اول ویجت مستطیل رو وارد کنم تا پشت جدول باشه.
p{direction:rtl; text-align:right;font-family:tahoma}. توی این فکرم که شاید راه بسیار ساده تری وجود داشته باشه. مثل وقتی که رویداد leaveEvent رو ندیده بودم و میخواستم خودم بنویسمش! :|
-
p{direction:rtl;text-align:right}. مگه شما بیشتر از 1 ویجت استفاده میکنید؟ نکنه برای هر مستطیل یک ویجت ایجاد میکنید؟
این کار درستی نیست. شما وقتی از paint استفاده میکنید یعنی اینکه راهی رو انتخاب کردین که اجزاء رو خودتون ترسیم کنید نه اینکه اول ویجت که رسم خودش رو داره ایجاد بشه بعد دوباره paint بشه.
این کاری که شما میخواید انجام بدین به نظر من باید از QGraphicsView و QGraphicsScene استفاده کنید. توی QGraphicsScene شما آبجکت ها رو تعریف میکنید و میتونید به عنوان delegate ازش چندین مورد ایجاد کنید و هر کدوم از QGraphicsItem ها event های خودشون رو دارن و میتونید کنترلشون کنید. علاوه بر اینها به شما امکانات transformation مثل scale و rotation رو هم میده.
با استفاده از اینها ابزاری تولید شده بنام QML که چون توی تولید این نوع کاربردها کار رو ساده میکنه بهش qtquick میگن.
حالا چرا از QML استفاده نمیکنید؟ -
p{direction:rtl; text-align:right;font-family:tahoma}. نه من فقط یک ویجت دارم که جدول و اطلاعات درون اون رو رسم میکنه. وقتی هم که میخواستم اون مستطیل بدون نیاز به ترسیم مجدد قابلیت حرکت داشته باشه کد ترسیم اون رو درون یک ویجت دیگه قرار دادم و از move استفاده کردم.
چرا باید QGraphicsScene رو داخل QGraphicsView اضافه کرد و بعد نمایش داد؟
چرا QGraphicsView زمینه سفید و حاشیه داره؟ البته حاشیه رو تونستم با استفاده از StyleSheet بردارم.
طبق راهنما:
@
QGraphicsScene *hicl = new QGraphicsScene(this);
hicl->addText("text");
QGraphicsView *hiclv = new QGraphicsView(hicl,this);
@p{direction:rtl; text-align:right;font-family:tahoma}. رویداد های QGraphicsView رو چطور کنترل کنم؟ و زمینه رو چطور حذف کنم؟
-
p{direction:rtl;text-align:right}. در واقع QGraphicsView یک نمایش دهنده برای QGraphicsScene هست که اون رو render میکنه و برای خروجی دادن حتی میتونه از openGL استفاده کنه.
برای شروع به example ها مراجعه کنید
http://doc.qt.digia.com/qt/examples-graphicsview.html -
p{direction:rtl; text-align:right;font-family:tahoma}. چطور یک ویجت میتونه با Parent خودش ارتباط برقرار کنه؟ مثلا مقدار یک متغییر از Parent رو تغییر بده یا تابعی از اون رو صدا بزنه. یا وقتی کلیک شد به Parent اطلاع بده. از طریق کلمه کلیدی Parent میشه ارتباط ایجاد کرد؟ یا باید از eventFilter در Parent استفاده کنم؟
-
[quote author="nice_2000" date="1357654368"]p{direction:rtl; text-align:right;font-family:tahoma}. چطور یک ویجت میتونه با Parent خودش ارتباط برقرار کنه؟ مثلا مقدار یک متغییر از Parent رو تغییر بده یا تابعی از اون رو صدا بزنه. یا وقتی کلیک شد به Parent اطلاع بده. از طریق کلمه کلیدی Parent میشه ارتباط ایجاد کرد؟ یا باید از eventFilter در Parent استفاده کنم؟[/quote]
p{direction:rtl; text-align:right;font-family:tahoma}. ۱. ما یه چیزی داریم به اسم Signal and Slot Mechanism
۲. داری کاملاً مسsر اشتباه رو میری. به بدترین شکل ممکن ویجت رو اپدیت میکنی. update policy رو فقط عوض کن. لازم نیست همهٔ ویجت رو یکجا آپدیت کنی. یک مستطیل از داخل ویجت رو هم میشه paint کرد.
۳. هیچ نیازی به QGraphicsView و QGraphicsScene نداری.
۴. کسی نمیتونه بدون دیدن کد و درک دقیق کاری که میخوای انجام بدی کمکت کنه. -
p{direction:rtl; text-align:right;font-family:tahoma}. اون Update Policy رو نفهمیدم :|
این کدش هست:
@
#include "widget.h"
#include <QPainter>
#include <QMouseEvent>
#include <math.h>
int cx=1,cy=1;
Widget::Widget(QWidget parent)
: QWidget(parent)
{
setMouseTracking(true);
}
Widget::~Widget()
{
}
void Widget::paintEvent(QPaintEvent ){
int x,y;
QPainter p(this);
for(x=0;x<7;x++){
for(y=0;y<6;y++){
p.drawRect(25x,20y,25,20);
p.drawText(25x,20y,25,20,Qt::AlignCenter,QString::number(x+y));
}
}
p.fillRect(cx,cy,24,19,Qt::green);
}
void Widget::mouseMoveEvent(QMouseEvent *ev){
cx=floor(ev->x()/25)*25+1;
cy=floor(ev->y()/20)*20+1;
update();
}
@ -
p{direction:rtl; text-align:right}. سلام دوست عزیز یک برنامه براتون نوشتم :
@
#include <QtGui/QApplication>
#include <QTableWidget>
#include <QHeaderView>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QTableWidget *tableWidget = new QTableWidget(5, 5);
tableWidget->horizontalHeader()->setVisible(false);
tableWidget->verticalHeader()->setVisible(false);
tableWidget->setStyleSheet("::item:hover{background-color: rgb(255, 0, 0);}");
tableWidget->show();
return a.exec();
}
@ -
p{direction:rtl; text-align:right;font-family:tahoma}. متشکرم تقریبا همون چیزیه که میخواستم.
جدول من مربوط به روز های یک ماه هست. تنها باید وقتی ماوس روی هر سلول رفت اون سلول Highlight بشه و وقتی کلیک شد یک کاری انجام بشه.
اما این جدول امکان ویرایش داره - امکان انتخاب چند سلول همزمان رو داره و زمینه داره که البته زیاد مهم نیست.
رویداد کلیکش رو هم هنوز تست نکردم که میشه تشخیص داد کدوم سلول کلیک شده یا نه.
شاید بتونم سفارش سازیش کنم...تست کردم. تمام موارد OK هست :)
اما یک مورد کوچک اضافه شد! وقتی ماوس رو میبرم روی یکی از سلول ها و انتخابش میکنم رنگ سلول به رنگ hover یعنی قرمز میمونه! وقتی یک سلول انتخاب شده دیگه لازم نیست با حرکت ماوس hover نشون بده. این رو هم میشه با StyleSheet درست کرد یا باید کد بنویسم؟
میخوام به ورودی Keyboard عکس العمل نشون نده و فقط با ماوس بشه باهاش کار کرد! باید eventFilter براش بذارم؟مشکل رنگ hover سلول انتخاب شده حل شد! بیخودی دارم سوال میکنم!
:D
p{direction:rtl; text-align:right;font-family:tahoma}. خب حالا چطور جلوی ورودی کیبورد رو بگیرم؟
این هم حل شد!!! :O