Daha çox

Qt widgetlarından dəyərlər əldə etmək və bufer üçün istifadə etmək


Tampon tapan sadə bir plagin yazıram. Mənim gui-də 2 birləşmiş qutu və 1 Xətt redaktəsi var. Birinci birləşmiş qutuda 'Vəziyyətlər' sütunundan dəyərlər açılır və 2-ci birləşmə 'Şəhərlər' sütunundan dəyərlər açılır. Diqqət yetirin ki, şəhərlər seçilmiş vəziyyətlərdən asılı olaraq birləşdirilmiş qutuda süzülür. Və 3rd Lineedit istifadəçidən bir məsafə alır. Nəticədə, istifadəçilərin lineedit qutusuna verilmiş 'məsafə dəyəri' göstərilən (2-ci birləşmiş qutudan) bufer istərdim. QGIS API-də QgsGeometryAnalyzer (). Buffer () funksiyasını sınadım. Ancaq ilk arqument yuxarıda göstərilən funksiya üçün bir təbəqədir. Bunun əvəzinə gui-lərimin şəhər kombinasiyasından və lineedit-dən dəyər alıb tampon tapmasını istəyirəm. Necə yerinə yetirmək olar. Uzun yazı üçün üzr istəyirəm.


Düşünürəm ki, bu sizə kömək edə bilər:

# Tampon məsafəsi və seçilmiş şəhər dist = float (myLineEdit.text ()) city = myComboBo.currentText () # Seçilmiş şəhərə uyğun xüsusiyyət əldə edin expr = QgsExpression ('"Cities" =  "+ city +' " ) it = myLayer.getFeatures (QgsFeatureRequest (expr)) feature = it.next () # Xüsusiyyət həndəsəsində bir tampon yerinə yetirmək myBufferPolygon = feature.geometry (). buffer (dist, 50)

Sonra istifadə edə bilərsinizmyBufferPolygonyeni bir xüsusiyyət yaratmaq və başqa bir vektor qatında və ya buna bənzər bir şeydə saxlamaq.


Qt Tez Səhnə Qrafik Quruluşu

Səhnə qrafiki hər biri xüsusi bir məqsədə xidmət edən əvvəlcədən təyin edilmiş bir sıra qovşaq növlərindən ibarətdir. Buna bir mənzərə qrafası kimi baxsaq da, daha dəqiq bir tərif düyün ağacıdır. Ağac QML səhnəsindəki QQuickItem növlərindən tikilir və daxili səhnə daha sonra səhnəni çəkən bir göstərici tərəfindən işlənir. Düyünlər özləri edir yox hər hansı bir aktiv rəsm kodu və ya virtual boya () funksiyası ehtiva edir.

Düyün ağacı daha çox mövcud Qt Quick QML növləri tərəfindən daxili olaraq qurulsa da, istifadəçilər üçün 3D modelləri təmsil edən alt ağaclar da daxil olmaqla öz məzmunu ilə tam alt ağacları əlavə etmək mümkündür.

Düyünlər

İstifadəçilər üçün ən vacib qovşaq QSGGeometryNode. Həndəsəsini və materialını təyin edərək xüsusi qrafikləri təyin etmək üçün istifadə olunur. Həndəsə QSGGeometry istifadə edərək təyin olunur və qrafik ibtidainin formasını və ya meshunu təsvir edir. Bir xətt, bir düzbucaqlı, bir çoxbucaqlı, bir çox əlaqəsi kəsilmiş düzbucaqlı və ya kompleks 3D mesh ola bilər. Material bu formadakı piksellərin necə doldurulduğunu təyin edir.

Bir düyünün istənilən sayda uşağı ola bilər və həndəsə düyünləri uşaqlarının arxasında valideynləri ilə uşaq qaydasında görünməsi üçün göstəriləcəkdir.

Qeyd: Bu, göstəricidəki faktiki göstərmə qaydası barədə heç nə demir. Yalnız əyani nəticəyə zəmanət verilir.

Səhnə qrafikində kəsmə funksiyasını həyata keçirir

Səhnə qrafasında göstərilən bütün məzmunda istifadə olunur

Səhnə qrafikindəki bütün qovşaqlar üçün əsas sinif

Düyünlərin qeyri-şəffaflığını dəyişdirmək üçün istifadə olunur

Səhnə qrafasında dəyişiklikləri həyata keçirir

Xüsusi qovşaqlar QQuickItem :: updatePaintNode () alt sinfi və QQuickItem :: ItemHasContents bayrağını təyin etməklə səhnə qrafikinə əlavə olunur.

Xəbərdarlıq: Doğma qrafika (OpenGL, Vulkan, Metal, və s.) Əməliyyatlarının və səhnə qrafiki ilə qarşılıqlı əlaqələrin yalnız göstərilən mövzuda, ilk növbədə updatePaintNode () çağırışı zamanı baş verməsi çox vacibdir. Əsas qayda yalnız QQuickItem :: updatePaintNode () funksiyası daxilində "QSG" prefiksi olan siniflərdən istifadə etməkdir.

Ön emal

Düyünlərdə səhnə qrafiki göstərilmədən əvvəl çağırılacaq virtual QSGNode :: preprocess () funksiyası var. Düyün alt sinifləri QSGNode :: UsePreprocess bayrağını təyin edə bilər və QSGNode :: preprocess () funksiyasını düyünlərinin son hazırlığını etmək üçün ləğv edə bilər. Məsələn, cari miqyas faktoru üçün bir bezier əyrisinin düzgün detal səviyyəsinə bölünməsi və ya bir toxumanın bir hissəsinin yenilənməsi.

Düyün mülkiyyəti

Düyünlərə sahiblik açıq şəkildə yaradıcı tərəfindən və ya QSGNode :: OwnedByParent bayrağını təyin etməklə səhnə qrafiki tərəfindən həyata keçirilir. Səhnə qrafiki üçün mülkiyyətin təyin edilməsi tez-tez üstünlük verilir, çünki səhnə qrafiki GUI ipindən kənarda olduqda təmizlənməni asanlaşdırır.

Materiallar

Material QSGGeometryNode-da bir həndəsənin daxili hissəsinin necə doldurulduğunu təsvir edir. Qrafika boru kəmərinin zirvəsi və parçalanma mərhələləri üçün qrafika kölgələdicilərini əhatə edir və əldə edilə bilən şeylərdə geniş bir elastiklik təmin edir, Qt Quick maddələrinin əksəriyyəti yalnız qatı rəng və toxuma doldurmaları kimi çox əsas materiallardan istifadə edir.

Yalnız bir QML Məhsul növünə xüsusi kölgələmə tətbiq etmək istəyən istifadəçilər üçün bunu ShaderEffect tipini istifadə edərək birbaşa QML-də etmək mümkündür.

Aşağıda material dərslərinin tam siyahısı verilmişdir:

Səhnə qrafikində düz rəngli həndəsə göstərməyin rahat yolu

Bir shader proqramı üçün göstərmə vəziyyətini kapsülləşdirir

Qrafik API-dən müstəqil bir shader proqramını təmsil edir

Göstəricidə bir OpenGL shader proqramını təmsil edir

QSGMaterial ilə birlikdə bənzərsiz bir nişan kimi istifadə olunur

Səhnə qrafasında toxumalı həndəsə göstərməyin rahat yolu

Səhnə qrafasında toxumalı həndəsə göstərməyin rahat yolu

Səhnə qrafasında vertex rəngli həndəsə göstərməyin rahat yolu

Rahatlıq qovşaqları

Səhnə qrafiki API səviyyədir və rahatlıqdan daha çox performansa diqqət yetirir. Xüsusi həndəsələr və materialları sıfırdan, hətta ən əsas olanlardan da yazmaq, əhəmiyyətsiz bir kod tələb edir. Bu səbəbdən API, ən çox yayılmış xüsusi qovşaqları hazır vəziyyətə gətirmək üçün bir neçə rahatlıq sinfi daxildir.

    - düz rəngli bir material ilə düzbucaqlı həndəsəni təyin edən bir QSGGeometryNode alt sinfi. - toxuma materialı ilə düzbucaqlı həndəsəni təyin edən bir QSGGeometryNode alt sinfi.

Üzv növü sənədləri

QWidget :: RenderFlag bayraqları QWidget :: RenderFlags

Bu enum, QWidget :: render () çağırarkən widgetın necə göstəriləcəyini izah edir.

SabitDəyərTəsvir
QWidget :: DrawWindowBackground 0x1 Bu seçimi aktiv etsəniz, autoFillBackground təyin olunmasa belə, widgetın arxa planı hədəfə çevrilir. Varsayılan olaraq, bu seçim aktivdir.
QWidget :: DrawChildren 0x2 Bu seçimi aktiv etsəniz, widgetın uşaqları hədəfə rekursiv olaraq göstərilir. Varsayılan olaraq, bu seçim aktivdir.
QWidget :: IgnoreMask 0x4 Bu seçimi aktiv etsəniz, hədəfə göstərilərkən widgetın QWidget :: mask () laqeyd qalır. Varsayılan olaraq, bu seçim deaktivdir.

Bu enum Qt 4.3-də təqdim edildi və ya dəyişdirildi.

RenderFlags növü, QFlags & ltRenderFlag & gt üçün yazılmış bir dərmandır. RenderFlag dəyərlərinin OR birləşməsini saxlayır.


Qt4 ilə C ++ GUI Proqramlaşdırma: Xüsusi Widgetların yaradılması

İkiqat buferləmə, widgetı ekrandan kənar bir pixmap-ə göstərmək və pixmap-ı ekrana köçürməkdən ibarət olan bir GUI proqramlaşdırma üsuludur. Qt-un əvvəlki versiyalarında bu texnika tez-tez titrəməni aradan qaldırmaq və daha sürətli bir istifadəçi interfeysi təmin etmək üçün istifadə olunurdu.

Qt 4-də, QWidget bunu avtomatik olaraq idarə edir, buna görə də widgetların titrəməsindən nadir hallarda narahat olmalıyıq. Hələ də, widgetın göstərilməsi mürəkkəbdirsə və təkrar-təkrar ehtiyac duyulursa, açıq cüt tamponlama faydalı qalır. Daha sonra bir pixmap'ı widget ilə daimi olaraq saxlaya bilərik, həmişə növbəti boya hadisəsinə hazır ola bilərik və hər hansı bir boya hadisəsi aldıqda widget'a kopyalayırıq. Bütün widgetın göstərilməsini təkrar-təkrar hesablamadan rezin lent çəkmək kimi kiçik dəyişikliklər etmək istədiyimiz zaman xüsusilə faydalıdır.

Bu fəsli nəzərdən keçirərək tamamlayacağıq Plotter rəqəmlər 5.7 və 5.9-da göstərilən xüsusi widget. Bu widget ikiqat tampondan istifadə edir və Qt proqramlaşdırma, klaviatura hadisələri ilə işləmə, əl düzümü və koordinat sistemləri daxil olmaqla bəzi digər cəhətləri nümayiş etdirir.

Burada etdiyimiz kimi xüsusi bir widget yaratmaq əvəzinə bir qrafika və ya plan qurma widgetına ehtiyac duyan real bir tətbiq üçün, çox güman ki, mövcud üçüncü tərəf widgetlarından birini istifadə edəcəyik. Məsələn, http://www.ics.com/ saytından GraphPak, http://www.kdab.net/ saytından KD Chart və ya http://qwt.sourceforge.net/ saytından Qwt istifadə edə bilərik.

The Plotter widget koordinatların vektorları kimi göstərilən bir və ya daha çox əyri göstərir. İstifadəçi şəklin üzərinə bir kauçuk lent çəkə bilər və Plotter rezin bantla əhatə olunmuş ərazini böyüdəcəkdir. İstifadəçi qrafada bir nöqtəyə basaraq, sol siçan düyməsini basıb siçanı başqa yerə sürükləyərək və siçan düyməsini buraxaraq rezin lent çəkir. Qt təmin edir QRubberBand rezin lentlər çəkmək üçün sinif, lakin burada görünüşü daha yaxşı idarə etmək və ikiqat buferliyi göstərmək üçün özümüz çəkirik.

İstifadəçi bir neçə dəfə bir rezin lent çəkərək təkrar-təkrar böyüdə bilər, istifadə edərək böyüdərək Kiçiltmə düyməsini basın və sonra Yaxınlaşdırmaq düyməsini basın. The YaxınlaşdırmaqKiçiltmə düymələr ilk dəfə əlçatan olduqda görünür ki, istifadəçi qrafiki böyütməsə ekranı qarışdırmasın.

The Plotter widget istənilən sayda döngə üçün məlumat saxlaya bilər. Ayrıca bir yığını saxlayır PlotSettings hər biri müəyyən bir zoom səviyyəsinə uyğun olan obyektlər.

Gəlin başlayaraq sinfi nəzərdən keçirək qurucu.h:

Plotterin başlıq sənədində istifadə olunan Qt sinifləri üçün başlıq sənədlərini daxil etməyə və başlıqda göstəriciləri və ya istinadları olan sinifləri irəli elan etməklə başlayırıq.

İçində Plotter sinif, süjet qurmaq üçün üç ümumi funksiya və böyütmək və uzaqlaşdırmaq üçün iki ümumi yuva təmin edirik. Biz də həyata keçiririk minimumSizeHint ()sizeHint () dan QWidget. Bir əyri nöqtəsini a kimi saxlayırıq QVector & ltQPointF & gt, harada QPointF üzən nöqtə versiyasıdır QPoint.

Sinifin qorunan hissəsində bütün elan edirik QWidget reallaşdırmaq istədiyimiz hadisə idarəediciləri.

Sinifin xüsusi hissəsində, widgetın, sabit və bir neçə üzv dəyişənin rənglənməsi üçün bir neçə funksiyanı elan edirik. The Haşiyə sabit qrafın ətrafında bir qədər boşluq təmin etmək üçün istifadə olunur.

Üzv dəyişənlər arasında pixmap növü QPixmap. Bu dəyişən, ekranda göstərilənlə eyni olan bütün widgetın göstərilməsinin bir nüsxəsini saxlayır. Süjet həmişə bu ekran xaricindəki pixmap üzərinə çəkilir, sonra pixmap widget üzərinə kopyalanır.

The PlotSettings sinif aralığını müəyyənləşdirir x- və y-axlar və bu oxlar üçün gənələrin sayı. Şəkil 5.8 a-nın uyğunluğunu göstərir PlotSettings obyekt və a Plotter widget.

Konvensiya ilə, numXTicksnumYTicks əgər birdirsə numXTicks 5, Plotter həqiqətən altı gənə işarəsi çəkəcəkdir x-aksis. Bu sonradan hesablamaları asanlaşdırır.

İndi tətbiqetmə sənədini nəzərdən keçirək:

The setBackgroundRole () zəng deyir QWidget paletin "qaranlıq" komponentini "pəncərə" komponenti əvəzinə, widgetı silmək üçün rəng kimi istifadə etmək. Bu, Qt-a widgetın daha böyük ölçüsünə dəyişdirildikdə yeni aşkarlanan pikselləri doldurmaq üçün istifadə edə biləcəyi standart bir rəng verir. boya hadisəsi () hətta yeni pikselləri çəkmək şansı var. Bizim də zəng etməyimiz lazımdır setAutoFillBackground (doğru) bu mexanizmi təmin etmək. (Varsayılan olaraq, uşaq widgetları arxa planı ana vidjetindən alır.)

The setSizePolicy () zəng widgetın ölçüsü siyasətini təyin edir QSizePolicy :: Genişlənir hər iki istiqamətdə. Bu, widgetdan məsul olan hər hansı bir plan menecerinə widgetın xüsusilə böyüməyə hazır olduğunu, eyni zamanda kiçilə biləcəyini söyləyir. Bu parametr, çox ekran yer tuta bilən widgetlar üçün tipikdir. Varsayılan budur QSizePolicy :: Tercih olunur hər iki istiqamətdə, bu da widgetın ölçüsü ipucu ölçüsünə üstünlük verdiyini, ancaq minimum ölçülü ipucuya endirilə biləcəyini və lazım olduqda müddətsiz genişlənə biləcəyini göstərir.

The setFocusPolicy (Qt :: StrongFocus) zəng vidceti tıklayaraq və ya basaraq fokus qəbul edir Tab. Zaman Plotter fokus var, əsas preslər üçün hadisələr alacaq. The Plotter widget bir neçə düyməni başa düşür: + böyütmək - böyütmək və ox düymələrini yuxarı, aşağı, sol və sağa sürüşdürmək üçün.

Hələ konstruktorda ikisini yaradırıq QToolButtons, hər birinin işarəsi var. Bu düymələr istifadəçinin böyüdüb böyütməsinə imkan verir. Düymələrin nişanları bir qaynaq sənədində saxlanılır, buna görə istifadə edən hər hansı bir tətbiq Plotter widgetın bu girişə ehtiyacı olacaq .pro fayl:

Resurs faylı, Spreadsheet tətbiqi üçün istifadə etdiyimizə bənzəyir:

The tənzimləmə ölçüsü () düymələrdəki çağırışlar ölçülərini ölçü göstərişlərinə uyğun olaraq təyin etdi. Düymələr əvəzinə bir düzüşə qoyulmur, onları əl ilə yerləşdirəcəyik PlotterTədbirin ölçüsünü dəyişdirmək. Heç bir tərtibat istifadə etmədiyimiz üçün düymələrin əsas hissəsini keçərək açıq şəkildə göstərməliyik bu üçün QToolButton qurucu.

Zəng setPlotSettings () sonunda başlatma tamamlayır.

The setPlotSettings () funksiyasını təyin etmək üçün istifadə olunur PlotSettings süjetin göstərilməsi üçün istifadə etmək. Bu adlanır Plotter qurucu və sinif istifadəçiləri tərəfindən çağırıla bilər. Plotter varsayılan zoom səviyyəsində başlayır. İstifadəçi böyüdükdə hər dəfə yeni PlotSettings instansiya yaradıldı və zoom yığınına qoyuldu. Zum yığını iki üzv dəyişən ilə təmsil olunur:

  • zoomStack fərqli zoom parametrlərini a kimi saxlayır QVector & ltPlotSettings & gt.
  • curZoom cərəyanı saxlayır PlotSettingsin indeksi zoomStack.

Zəngdən sonra setPlotSettings (), zoom yığını yalnız bir giriş və YaxınlaşdırmaqKiçiltmə düymələr gizlidir. Biz zəng edənə qədər bu düymələr göstərilməyəcək göstərmək () onlarda yaxınlaşdırmaq()yaxınlaşdır () yuvalar. (Normalda zəng etmək kifayətdir göstərmək () bütün uşaqları göstərmək üçün üst səviyyəli widgetda. Ancaq açıq şəkildə zəng etdiyimiz zaman gizlət () bir uşaq widgetında, zəng vurana qədər gizlidir göstərmək () üzərində.)

Zəng refreshPixmap () ekranı yeniləmək üçün lazımdır. Adətən zəng edərdik yeniləmə (), amma burada saxlamaq istədiyimiz üçün biraz fərqli şeylər edirik QPixmap hər zaman aktualdır. Piksel xəritəsini bərpa etdikdən sonra refreshPixmap () zənglər yeniləmə () pixmap-ı widget üzərinə kopyalamaq üçün.

The yaxınlaşdır () qrafın yaxınlaşdırılması halında yuva böyüdülür. Cari yaxınlaşma səviyyəsini azaldır və imkan verir Kiçiltmə qrafın daha da uzadıla biləcəyinə və ya olmasına bağlı olaraq düymə. The Yaxınlaşdırmaq düyməsini aktivləşdirir və göstərir və ekran bir zəng ilə yenilənir refreshPixmap ().

İstifadəçi əvvəllər böyüdüb yenidən uzaqlaşdırdısa PlotSettings növbəti zoom səviyyəsi yaxınlaşma yığınında olacaq və böyüdə bilərik. (Əks təqdirdə, rezin lentdən istifadə edərək böyütmək mümkündür.)

Yuva artır curZoom yaxınlaşdırma yığınına bir səviyyə daha dərindən keçmək üçün Yaxınlaşdırmaq düyməsini aktivləşdirmək və ya daha da yaxınlaşdırmağın mümkün olub-olmamasına bağlı olaraq aktivləşdirir və göstərir Kiçiltmə düyməsini basın. Yenə də zəng edirik refreshPixmap () çizicinin ən yaxın zoom parametrlərindən istifadə etməsini təmin etmək.

The setCurveData () funksiyası müəyyən bir əyri identifikatoru üçün əyri məlumatlarını təyin edir. Eyni identifikatora sahib bir əyri artıq mövcuddursa əyri xəritə, əks halda yeni əyri məlumatları ilə əvəz olunur, yeni əyri sadəcə daxil edilir. The əyri xəritə üzv dəyişən tiplidir QMap & ltint, QVector & ltQPointF & gt & gt.

The clearCurve () funksiya göstərilən döngəni döngə xəritəsindən çıxarır.

The minimumSizeHint () funksiyası sizeHint (). Elə bunun kimi sizeHint () bir widgetın ideal ölçüsünü təyin edir, minimumSizeHint () bir widgetın ideal minimum ölçüsünü təyin edir. Düzen heç vaxt bir widgetı minimum ölçüsü işarə altına salmaz.

Döndüyümüz dəyər 300 x 200-dir (bəri Haşiyə dördüncü tərəfin kənarına və sahənin özü üçün bir az boşluğa imkan vermək üçün 50) bərabərdir. Bu ölçünün altında süjet faydalı ola bilməyəcək qədər kiçik olardı.

İldə sizeHint (), nisbətində bir "ideal" ölçüsünü qaytarırıq Haşiyə sabit və eyni sevindirici 3: 2 nisbət nisbətində üçün istifadə etdik minimumSizeHint ().

Bu.-Nin nəzərdən keçirilməsini bitirir Plotterictimai funksiyalar və yuvalar. İndi qorunan hadisə işləyicilərini nəzərdən keçirək.

Rezin bant görünürsə, onu süjetin üstünə çəkirik. "Qaranlıq" fonla yaxşı ziddiyyət yaratmaq üçün qələm rəngi olaraq widgetın cari rəng qrupundan "yüngül" komponentdən istifadə edirik. Diqqət yetirin ki, ekrandan kənar pixmap toxunmadan, birbaşa widget üzərində çəkirik. Istifadə olunur QRect :: normallaşdırılmış () rezin bant düzbucaqlının müsbət eni və hündürlüyünü təmin edir (lazım olduqda koordinatları dəyişdirmə) və düzəldilmişdir () düzbucaqlının ölçüsünü bir piksel enində öz konturuna imkan vermək üçün bir piksel azaldır.

Əgər Plotter fokus var, widget stili istifadə edərək fokus düzbucağı çəkilir drawPrimitive () ilə işləyin QStyle :: PE_FrameFocusRect ilk arqument kimi və a QStyleOptionFocusRect ikinci arqument kimi obyekt. Fokus düzbucağlının rəsm seçimləri əsasında qurulur Plotter widget (tərəfindən initFrom () zəng edin). Arxa fon rəngi açıq şəkildə göstərilməlidir.

Mövcud üslubdan istifadə edərək boya çəkmək istədikdə ya a zəng edə bilərik QStyle birbaşa fəaliyyət göstərir, məsələn,

və ya istifadə edin QStylePainter normal yerinə QPainter, etdiyimiz kimi Plotter, və istifadə edərək daha rahat boya.

The QWidget :: stil () function, widgetı çəkmək üçün istifadə edilməli olan üslubu qaytarır. Qt-də bir widget stili alt sinifdir QStyle. Daxili üslublar daxildir QWindowsStyle, QWindowsXPStyle, QWindowsVistaStyle, QMotifStyle, QCDEStyle, QMacStyle, QPlastiqueStyleQCleanlooksStyle. Hər üslub, içindəki virtual funksiyaları təkrarlayır QStyle tərzi üslub etdiyi platformaya uyğun şəkildə rəsmini yerinə yetirmək. QStylePainter's drawPrimitive () funksiyası QStyle panellər, düymələr və fokus düzbucaqlıları kimi "ibtidai elementlər" çəkmək üçün istifadə edilə bilən eyni adlı funksiya. Widget stili ümumiyyətlə bir tətbiqdəki bütün widgets üçün eynidır (QApplication :: style ()), lakin istifadə edərək hər bir widget əsasında ləğv edilə bilər QWidget :: setStyle ().

Alt sinifləşdirmə ilə QStyle, xüsusi bir üslub təyin etmək mümkündür. Bu, bir tətbiqə və ya bir tətbiq paketinə fərqli bir görünüş vermək üçün edilə bilər, Fəsil 19-da görəcəyimiz kimi. Hədəf platformanın yerli görünüşündən istifadə etmək məsləhətdir, istəsəniz Qt çox rahatlıq təklif edir. sərgüzəştli olmaq.

Qt-un daxili widgetları demək olar ki, yalnız etibar edir QStyle özlərini boyamaq. Bu səbəbdən Qt tərəfindən dəstəklənən bütün platformalarda yerli widgetlara bənzəyirlər. Xüsusi widgetlar ya istifadə edərək üslubdan xəbərdar edilə bilər QStyle özlərini boyamaq və ya daxili Qt widgetlarını uşaq widgetları olaraq istifadə etmək. Üçün Plotter, hər iki yanaşmanın birləşməsindən istifadə edirik: Fokus düzbucağı istifadə edərək çəkilir QStyle (a. vasitəsilə QStylePainter), və YaxınlaşdırmaqKiçiltmə düymələr daxili Qt widgetlarıdır.

Hər zaman Plotter widget ölçüsü dəyişdirildi, Qt bir "ölçüsünü dəyişdirmə" hadisəsi yaradır. Budur, yenidən həyata keçiririk resizeEvent () yerləşdirmək YaxınlaşdırmaqKiçiltmə düyməsinin sağ üst hissəsində Plotter widget.

Biz hərəkət edirik Yaxınlaşdırmaq düyməsini və Kiçiltmə düyməni 5 piksel boşluğu ilə ayrılmış və ana widgetın yuxarı və sağ kənarlarından 5 piksellik ofsetlə yan-yana qoymaq üçün.

Düymələrin koordinatları (0, 0) olan yuxarı sol küncdə köklü qalmasını istəsəydik, sadəcə onları Plotter qurucu. Ancaq koordinatları widgetın ölçüsündən asılı olan yuxarı sağ küncdə izləmək istəyirik. Bu səbəbdən yenidən tətbiq etmək lazımdır resizeEvent () və düymələrin mövqeyini orada təyin etmək.

İçərisindəki düymələr üçün heç bir mövqe təyin etmədik Plotter qurucu. Bu, problem deyil, çünki Qt həmişə bir widget ilk dəfə göstərilmədən əvvəl bir ölçüsünü dəyişdirir.

Yenidən həyata keçirməyə alternativdir resizeEvent () və uşaq widgetlarını əl ilə düzəltmək, bir layout menecerindən istifadə etmək olardı (məsələn, QGridLayout). Bir düzeni istifadə etmək biraz daha mürəkkəb olardı və digər tərəfdən daha çox qaynaq istehlak edərdi, ərəb və ibrani kimi dillər üçün lazım olan sağdan sola düzülüşləri əla şəkildə idarə edərdi.

Sonda zəng edirik refreshPixmap () pixmap-i yeni ölçüdə yenidən çəkmək üçün.

İstifadəçi sol siçan düyməsini basdıqda, bir kauçuk bant göstərməyə başlayırıq. Bu qəbulu əhatə edir rezinBandIsShown üçün doğru, başlanğıc rubberBandRect cari siçan göstəricisi mövqeyi ilə üzv dəyişən, rezin lentin boyanması üçün bir boya hadisəsinin planlaşdırılması və siçan imlecinin bir çarpaz formasına sahib olması.

The rubberBandRect dəyişən tiplidir QRect. A QRect ya (kimi müəyyən edilə bilərx, y, eni, hündürlük) dörd dəfə və # 8212 yerdə (x, y) yuxarı sol küncün və eni x hündürlük düzbucaqlının ölçüsüdür və ya yuxarı sol və alt sağ koordinat cütüdür. Burada koordinat cütlüyünün təqdimatından istifadə etdik. İstifadəçinin həm yuxarı sol künc, həm də sağ alt künc kimi tıkladığı nöqtəni təyin etdik. Sonra zəng edirik updateRubberBandRegion () rezin bantla örtülmüş (kiçik) sahənin yenidən rənglənməsinə məcbur etmək.

Qt, siçan imlecinin formasını idarə etmək üçün iki mexanizm təmin edir:

  • QWidget :: setCursor () siçan müəyyən bir widget üzərində hərəkət edərkən istifadə etmək üçün imlec formasını təyin edir. Bir widget üçün heç bir kursor təyin edilməyibsə, ana widgetın imleci istifadə olunur. Üst səviyyə widgetlar üçün standart bir ox imlecidir.
  • QApplication :: setOverrideCursor () bütün tətbiq üçün imlec formasını təyin edir, bu vaxta qədər fərdi widgetlar tərəfindən təyin olunan imlecləri ləğv edir restoreOverrideCursor () adlanır.

Fəsil 4-də biz zəng etdik QApplication :: setOverrideCursor () ilə Qt :: WaitCursor tətbiqin imlecini standart gözləmə imlecinə dəyişdirmək.

İstifadəçi sol düyməni basıb siçan imlecini hərəkətə gətirəndə əvvəlcə zəng edirik updateRubberBandRegion () rezin lentin olduğu ərazini yenidən rəngləmək üçün bir boya tədbiri təyin etmək üçün yenidən hesablayırıq rubberBandRect siçan hərəkətini hesablamaq üçün və nəhayət çağırırıq updateRubberBandRegion () rezin bantın hərəkət etdiyi ərazini ikinci dəfə boyamaq üçün. Bu rezin bantı effektiv şəkildə silir və yeni koordinatlarda yenidən çəkir.

İstifadəçi siçanı yuxarı və ya sola aparırsa, çox güman ki rubberBandRectNominal alt sağ künc yuxarı sol küncünün yuxarı hissəsində və ya solunda bitəcəkdir. Bu baş verərsə QRect mənfi eni və ya hündürlüyü olacaqdır. İstifadə etdik QRect :: normallaşdırılmış () in boya hadisəsi () yuxarı-sol və sağ alt koordinatların mənfi olmayan genişlik və hündürlük əldə etmək üçün tənzimlənməsini təmin etmək.

İstifadəçi sol siçan düyməsini buraxdıqda, kauçuk bantı silirik və standart ox imlecini bərpa edirik. Rezin bant ən azı 4 x 4 olarsa, böyüdücüyü yerinə yetiririk. Rezin bant bundan kiçikdirsə, ehtimal ki, istifadəçi səhvən widgetı tıkladı və ya diqqətini ona yönəltdi, buna görə heç nə etmirik.

Zoomu yerinə yetirmək üçün kod bir az mürəkkəbdir. Bunun səbəbi, eyni zamanda widget koordinatları və plotter koordinatları ilə məşğul olmağımızdır. Burada həyata keçirdiyimiz işlərin əksəriyyəti rubberBandRect widget koordinatlarından plotter koordinatlarına. Dönüşüm etdikdən sonra zəng edirik PlotSettings :: tənzimlə () nömrələri yuvarlaqlaşdırmaq və hər ox üçün həssas sayda gənə tapmaq. Rəqəmlər 5.10 və 5.11 prosesi təsvir edir.

Şəkil 5.10 Kauçuk lentin widgetdan plotter koordinatlarına çevrilməsi

Şəkil 5.11 Plotter koordinatlarının tənzimlənməsi və rezin bantın yaxınlaşdırılması

Sonra zoomu həyata keçiririk. Zoom yenisini basmaqla əldə edilir PlotSettings yaxınlaşma yığınının üstündə hesabladığımızı və zəng etdiyimizi yaxınlaşdırmaq() işi görmək.

İstifadəçi bir düyməni basdıqda Plotter widget fokusa malikdir keyPressEvent () funksiyası deyilir. Altı düyməyə cavab vermək üçün onu yenidən tətbiq edirik: +, -, Yuxarı, Aşağı, SolDüzdü. İstifadəçi idarə etmədiyimiz bir düyməni basdısa, əsas sinif tətbiqini çağırırıq. Sadəlik üçün Shift, CtrlAlt vasitəsilə mövcud olan dəyişdirici düymələr QKeyEvent :: dəyişdiricilər ().

Siçan çarxı döndükdə təkər hadisələri baş verir. Siçanların əksəriyyəti yalnız şaquli təkər təmin edir, bəzilərində isə üfüqi təkər var. Qt hər iki təkəri də dəstəkləyir. Təkər hadisələri diqqət mərkəzində olan widgeta gedir. The delta () funksiya təkərin səkkizinci dərəcədə döndüyü məsafəni qaytarır. Siçanlar ümumiyyətlə 15 dərəcə addımlarla işləyirlər. Burada, yaxınlaşdırma yığınının ən üst hissəsini dəyişdirərək tələb olunan gənə sayına görə hərəkət edirik və ekranı istifadə edərək yeniləyirik. refreshPixmap ().

Siçan çarxının ən geniş yayılmış istifadəsi sürüşmə çubuğunu sürüşdürməkdir. Nə zaman istifadə edirik QScrollArea (Fəsil 6-da əhatə olunmuşdur) sürüşmə çubuqlarını təmin etmək, QScrollArea siçan çarxı hadisələrini avtomatik olaraq idarə edir, buna görə yenidən tətbiq etməyə ehtiyacımız yoxdur wheelEvent () özümüz.

Bu hadisə işləyicilərinin tətbiqini tamamlayır. İndi xüsusi funksiyaları nəzərdən keçirək.

The updateRubberBand () funksiyası mousePressEvent (), mouseMoveEvent ()mouseReleaseEvent () rezin bandı silmək və ya yenidən çəkmək üçün. Dörd zəngdən ibarətdir yeniləmə () rezin bantla örtülmüş dörd kiçik düzbucaqlı sahə üçün bir boya tədbiri planlaşdırır (iki şaquli və iki üfüqi xətt).

The refreshPixmap () funksiya süjetini ekran xaricindəki pixmap üzərinə yenidən çəkir və ekranı yeniləyir. Piksel xəritəsini widget ilə eyni ölçüyə uyğunlaşdırırıq və onu widgetın silmə rəngi ilə doldururuq. Bu rəng palitranın "qaranlıq" komponentidir, çünki çağırış edilir setBackgroundRole () içində Plotter qurucu. Arxa plan qatı olmayan bir fırça olarsa, QPixmap :: fill () fırça naxışını düzgün bir şəkildə düzəltmək üçün pixmap-in bitəcəyi widgetdakı ofseti bilməlidir. Burada, pixmap bütün widgeta uyğundur, buna görə (0, 0) mövqeyini təyin edirik.

Sonra a yaradırıq QPainter pixmap üzərində çəkmək. The initFrom () zəng, rəssamın qələmini, arxa planını və şriftini eyni ilə təyin edir Plotter widget. Sonra zəng edirik drawGrid ()drawCurves () rəsm çəkmək. Sonda zəng edirik yeniləmə () bütün widget üçün bir boya tədbiri təyin etmək. Pixmap, içindəki widgeta kopyalanır boya hadisəsi () funksiyası (s. 128).

The drawGrid () funksiya ızgaranı əyrilərin və oxların arxasında çəkir. Izgaranın çəkildiyi sahə ilə təyin olunur düz. Widget qrafiki yerləşəcək qədər böyük deyilsə, dərhal qayıdırıq.

Birinci üçün loop ızgaranın şaquli xəttlərini və gənələri boyunca çəkir x-aksis. İkinci üçün loop ızgaranın üfüqi xəttlərini və gənələri boyunca çəkir y-aksis. Sonda, haşiyələr boyunca bir düzbucaqlı çəkirik. The drawText () funksiyası hər iki oxda gənə işarələrinə uyğun rəqəmlər çəkmək üçün istifadə olunur.

Zənglər drawText () aşağıdakı sintaksisə sahib olun:

harada ( x, y, eni, hündürlük) düzbucaqlı təyin etmək, hizalama mətnin bu düzbucaqlı içindəki yeri və mətn çəkmək üçün mətn. Bu nümunədə mətni əl ilə çəkmək üçün daha uyğunlaşa bilən bir alternativ, mətnin sərhəd düzbucağını istifadə edərək hesablamağı əhatə edəcək düzbucağı hesabladıq QFontMetrics.

The drawCurves () funksiya ızgaranın üstündəki əyriləri çəkir. Zəng etməklə başlayırıq setClipRect () qurmaq QPainterDöngələri ehtiva edən düzbucaqlının klip bölgəsi (haşiyələr və qrafaqdakı çərçivə xaricində). QPainter daha sonra ərazidən kənar piksellər üzərində rəsm əməliyyatları görməzlikdən gələcəkdir.

Sonra, Java tərzli bir iterator istifadə edərək bütün əyrilər üzərində təkrarlayırıq və hər bir döngə üçün onun tərkib hissəsi üzərində təkrarlayırıq QPointFs. Biz iterator deyirik açar () əyri şəxsiyyət vəsiqəsini almaq funksiyası dəyər () müvafiq əyri məlumatlarını a kimi götürmək funksiyası QVector & ltQPointF & gt. Daxili üçün loop hər birini çevirir QPointF plotter koordinatlarından widget koordinatlarına qədər və bunları içəridə saxlayır polilin dəyişən.

Bir döngənin bütün nöqtələrini vidjet koordinatlarına çevirdikdən sonra döngə üçün qələm rəngi təyin etdik (əvvəlcədən təyin olunmuş rənglər dəstindən birini istifadə edərək) drawPolyline () bütün əyri nöqtələrdən keçən bir xətt çəkmək.

Bu tamamlandı Plotter sinif. Qalan yalnız bir neçə funksiyadır PlotSettings.

The PlotSettings konstruktor hər iki oxu da 0 ilə 10 aralığında beş gənə işarəsi ilə işə salır.

The fırladın () funksiya artımları (və ya azalmalar) minX, maxX, azmaxY iki gənə arasındakı intervala verilən saydan çoxdur. Bu funksiya daxilində kaydırmayı həyata keçirmək üçün istifadə olunur Plotter :: keyPressEvent ().

The tənzimləmək () funksiyası mouseReleaseEvent () yuvarlamaq minX, maxX, azmaxY dəyərlər "gözəl" dəyərlərə və hər ox üçün uyğun gənə sayını təyin etmək. Xüsusi funksiya adjustAxis () işini hər dəfə bir ox edir.

The adjustAxis () funksiyası onu çevirir dəqmaks parametrləri "gözəl" rəqəmlərə daxil edir və onu təyin edir numTicks verilənlərə uyğun hesabladığı gənələrin sayına görə parametr [dəq, maks] aralığı. Çünki adjustAxis () həqiqi dəyişənləri dəyişdirməlidir (minX, maxX, numXTicksvə s.) və yalnız nüsxələr deyil, parametrləri daimi olmayan istinadlardır.

Kodun çox hissəsi adjustAxis () sadəcə iki gənə arasındakı interval üçün uyğun bir dəyəri təyin etməyə çalışır ("addım"). Ox boyunca gözəl rəqəmlər əldə etmək üçün addımı diqqətlə seçməliyik. Məsələn, 3.8 addım dəyəri 3.8-dən çox olan bir oxa gətirib çıxarır və bu, insanların əlaqəsi çətin olur. Onluq qeyd ilə işarələnmiş oxlar üçün "gözəl" addım dəyərləri 10 formasının nömrələridir n , 2 & middot10 n , ya da 5 & middot10 n .

Addım dəyəri üçün bir növ maksimum dərəcədə olan "ümumi addım" ı hesablamaqla başlayırıq. Sonra formanın 10 uyğun nömrəsini tapırıq n ümumi addımdan kiçik və ya ona bərabərdir. Bunu ümumi addımın ondalık loqaritmasını götürərək, bu dəyəri bütöv bir ədədə yuvarlaqlaşdıraraq, sonra bu yuvarlatılmış ədədin gücünə 10-a qaldıraraq edirik. Məsələn, ümumi addım 236 olarsa, log 236 = 2.37291 hesablayırıq. sonra onu 2-yə yuvarlaqlaşdırırıq və 10 formasının namizəd addım qiyməti olaraq 10 2 = 100 əldə edirik n .

İlk namizəd addım dəyərinə sahib olduqdan sonra digər iki namizədi hesablamaq üçün istifadə edə bilərik: 2 & middot10 n və 5 & middot10 n . Əvvəlki nümunə üçün digər iki namizəd 200 və 500-dür. 500 namizəd ümumi addımdan daha böyükdür, buna görə istifadə edə bilmərik. Ancaq 200, 236-dan kiçikdir, buna görə bu nümunədəki addım ölçüsü üçün 200 istifadə edirik.

Hesablamaq olduqca asandır numTicks, dəqmaks addım dəyərindən. Yeni dəq dəyər orijinalın yuvarlaqlaşdırılması ilə əldə edilir dəq addımın ən yaxın qatına və yeni maks dəyər addımın ən yaxın qatına qədər yuvarlaqlaşdırma yolu ilə əldə edilir. Yeni numTicks yuvarlaqlaşdırılan arasındakı fasilələrin sayıdır dəqmaks dəyərlər. Məsələn, əgər dəq 240 və maks funksiyaya girdikdən sonra 1184 olur, yeni sıra beş gənə işarəsi ilə [200, 1200] olur.

Bu alqoritm bəzi hallarda suboptimal nəticələr verəcəkdir. Daha inkişaf etmiş bir alqoritm Paul S. Heckbert-in "Qrafik Etiketləri Üçün Gözəl Nömrələr" adlı məqaləsində təsvir edilmişdir. Qrafik Daşlar (Morgan Kaufmann, 1990).

Bu fəsil bizi kitabın I hissəsinin sonuna gətirir. Mövcud bir Qt widgetını necə özelleştirebileceğinizi və yerdən bir widget istifadə edərək necə quracağınızı izah etdi QWidget əsas sinif kimi. Layihə menecerlərindən istifadə edərək uşaq widgetlarının necə yerləşdiriləcəyini Fəsil 2-də gördük və mövzunu Fəsil 6-da daha da araşdıracağıq.

Bu nöqtədə Qt istifadə edərək tam GUI tətbiqetmələrini yazmaq üçün kifayət qədər məlumatımız var. II və III hissələrdə Qt gücündən tam istifadə edə bilmək üçün Qt-ı daha dərindən araşdıracağıq.


Qt4 ilə C ++ GUI Proqramlaşdırma: Xüsusi Widgetların yaradılması

Yerli Qt widgetları və ya digər xüsusi widgetlar olsun, bir çox xüsusi widget sadəcə mövcud widgetların birləşməsidir. HexSpinBox. Mövcud widgetlar tərtib edilərək hazırlanmış xüsusi widgetlar ümumiyyətlə inkişaf etdirilə bilər Qt Designer:

  1. "Widget" şablonunu istifadə edərək yeni bir forma yaradın.
  2. Lazımi widgetları formaya əlavə edin və düzün.
  3. Siqnalları və yuva əlaqələrini qurun.
  4. Siqnallar və yuvalar vasitəsilə əldə edilə bilən şeydən kənar davranış tələb olunursa, hər ikisindən irəli gələn bir sinifə lazımi kodu yazın QWidgetuic- nəsil.

Təbii ki, mövcud widgetları birləşdirmək də tamamilə kod şəklində edilə bilər. Hansı yanaşma götürülsə, nəticə a QWidget alt sinif.

If the widget has no signals and slots of its own and doesn't reimplement any virtual functions, it is even possible to simply assemble the widget by combining existing widgets without a subclass. That's the approach we used in Chapter 1 to create the Age application, with a QWidget, a QSpinBox, and a QSlider. Even so, we could just as easily have subclassed QWidget and created the QSpinBoxQSlider in the subclass's constructor.

When none of Qt's widgets are suitable for the task at hand, and when there is no way to combine or adapt existing widgets to obtain the desired result, we can still create the widget we want. This is achieved by subclassing QWidget and reimplementing a few event handlers to paint the widget and to respond to mouse clicks. This approach gives us complete freedom to define and control both the appearance and the behavior of our widget. Qt's built-in widgets, such as QLabel, QPushButtonQTableWidget, are implemented this way. If they didn't exist in Qt, it would still be possible to create them ourselves using the public functions provided by QWidget in a completely platform-independent manner.

To demonstrate how to write a custom widget using this approach, we will create the IconEditor widget shown in Figure 5.2. The IconEditor is a widget that could be used in an icon editing program.

In practice, before diving in and creating a custom widget, it is always worth checking whether the widget is already available, either as a Qt Solution (http://www.trolltech.com/products/qt/addon/solutions/catalog/4/) or from a commercial or non-commercial third party (http://www.trolltech.com/products/qt/3rdparty/), since this could save a lot of time and effort. In this case, we will assume that no suitable widget is available, and so we will create our own.

Let's begin by reviewing the header file.

The IconEditor class uses the Q_PROPERTY() macro to declare three custom properties: penColor, iconImagezoomFactor. Each property has a data type, a "read" function, and an optional "write" function. For example, the penColor property is of type QColor and can be read and written using the penColor()setPenColor() functions.

When we make use of the widget in Qt Designer, custom properties appear in Qt Designer's property editor below the properties inherited from QWidget. Properties may be of any type supported by QVariant. The Q_OBJECT macro is necessary for classes that define properties.

IconEditor reimplements three protected functions from QWidget and has a few private functions and variables. The three private variables hold the values of the three properties.

The implementation file begins with the IconEditor's constructor:

The constructor has some subtle aspects, such as the Qt::WA_StaticContents attribute and the setSizePolicy() call. We will discuss them shortly.

The pen color is set to black. The zoom factor is set to 8, meaning that each pixel in the icon will be rendered as an 8 x 8 square.

The icon data is stored in the image member variable and can be accessed through the setIconImage()iconImage() functions. An icon editor program would typically call setIconImage() when the user opens an icon file and iconImage() to retrieve the icon when the user wants to save it. The image variable is of type QImage. We initialize it to 16 x 16 pixels and 32-bit ARGB format, a format that supports semi-transparency. We clear the image data by filling it with a transparent color.

The QImage class stores an image in a hardware-independent fashion. It can be set to use a 1-bit, 8-bit, or 32-bit depth. An image with 32-bit depth uses 8 bits for each of the red, green, and blue components of a pixel. The remaining 8 bits store the pixel's alpha component (opacity). For example, a pure red color's red, green, blue, and alpha components have the values 255, 0, 0, and 255. In Qt, this color can be specified as

or, since the color is opaque, as

QRgb is simply a typedef for unsigned intqRgb()qRgba() are inline functions that combine their arguments into one 32-bit ARGB integer value. It is also possible to write

where the first FF corresponds to the alpha component and the second FF to the red component. İçində IconEditor constructor, we fill the QImage with a transparent color by using 0 as the alpha component.

Qt provides two types for storing colors: QRgbQColor. Whereas QRgb is only a typedef used in QImage to store 32-bit pixel data, QColor is a class with many useful functions and is widely used in Qt to store colors. İçində IconEditor widget, we use QRgb only when dealing with the QImage we use QColor for everything else, including the penColor property.

The sizeHint() function is reimplemented from QWidget and returns the ideal size of a widget. Here, we take the image size multiplied by the zoom factor, with one extra pixel in each direction to accommodate a grid if the zoom factor is 3 or more. (We don't show a grid if the zoom factor is 2 or 1, because then the grid would leave hardly any room for the icon's pixels.)

A widget's size hint is mostly useful in conjunction with layouts. Qt's layout managers try as much as possible to respect a widget's size hint when they lay out a form's child widgets. Üçün IconEditor to be a good layout citizen, it must report a credible size hint.

In addition to the size hint, widgets have a size policy that tells the layout system whether they like to be stretched and shrunk. By calling setSizePolicy() in the constructor with QSizePolicy::Minimum as horizontal and vertical policies, we tell any layout manager that is responsible for this widget that the widget's size hint is really its minimum size. In other words, the widget can be stretched if required, but it should never shrink below the size hint. This can be overridden in Qt Designer by setting the widget's sizePolicy property. We explain the meaning of the various size policies in Chapter 6.

The setPenColor() function sets the current pen color. The color will be used for newly drawn pixels.

The setIconImage() function sets the image to edit. We call convertToFormat() to make the image 32-bit with an alpha buffer, if it isn't already. Elsewhere in the code, we will assume that the image data is stored as 32-bit ARGB values.

After setting the image variable, we call QWidget::update() to schedule a repainting of the widget using the new image. Next, we call QWidget::updateGeometry() to tell any layout that contains the widget that the widget's size hint has changed. The layout will then automatically adapt to the new size hint.

The setZoomFactor() function sets the zoom factor for the image. To prevent division by zero elsewhere, we correct any value below 1. Again, we call update()updateGeometry() to repaint the widget and to notify any managing layout about the size hint change.

The penColor(), iconImage()zoomFactor() functions are implemented as inline functions in the header file.

We will now review the code for the paintEvent() funksiya. This function is IconEditor's most important function. It is called whenever the widget needs repainting. The default implementation in QWidget does nothing, leaving the widget blank.

Just like closeEvent(), which we met in Chapter 3, paintEvent() is an event handler. Qt has many other event handlers, each of which corresponds to a different type of event. Chapter 7 covers event processing in depth.

There are many situations when a paint event is generated and paintEvent() is called. For example:

  • When a widget is shown for the first time, the system automatically generates a paint event to force the widget to paint itself.
  • When a widget is resized, the system generates a paint event.
  • If the widget is obscured by another window and then revealed again, a paint event is generated for the area that was hidden (unless the window system stored the area).

We can also force a paint event by calling QWidget::update() və ya QWidget::repaint(). The difference between these two functions is that repaint() forces an immediate repaint, whereas update() simply schedules a paint event for when Qt next processes events. (Both functions do nothing if the widget isn't visible on-screen.) If update() is called multiple times, Qt compresses the consecutive paint events into a single paint event to avoid flicker. İldə IconEditor, we always use update().

We start by constructing a QPainter object on the widget. If the zoom factor is 3 or more, we draw the horizontal and vertical lines that form the grid using the QPainter::drawLine() funksiya.

A call to QPainter::drawLine() has the following syntax:

where ( x1, y1) is the position of one end of the line and ( x2, y2) is the position of the other end. There is also an overloaded version of the function that takes two QPoints instead of four ints.

The top-left pixel of a Qt widget is located at position (0, 0), and the bottom-right pixel is located at (width() - 1, height() - 1). This is similar to the conventional Cartesian coordinate system, but upside down, as Figure 5.3 illustrates. We can change QPainter's coordinate system by using transformations, such as translation, scaling, rotation, and shearing. We cover these in Chapter 8.

Before we call drawLine() on the QPainter, we set the line's color using setPen(). We could hard-code a color, such as black or gray, but a better approach is to use the widget's palette.

Every widget is equipped with a palette that specifies which colors should be used for what. For example, there is a palette entry for the background color of widgets (usually light gray) and one for the color of text on that background (usually black). By default, a widget's palette adopts the window system's color scheme. By using colors from the palette, we ensure that IconEditor respects the user's preferences.

A widget's palette consists of three color groups: active, inactive, and disabled. Which color group should be used depends on the widget's current state:

  • The Active group is used for widgets in the currently active window.
  • The Inactive group is used for widgets in the other windows.
  • The Disabled group is used for disabled widgets in any window.

The QWidget::palette() function returns the widget's palette as a QPalette object. Color groups are specified as enums of type QPalette::ColorGroup.

When we want to get an appropriate brush or color for drawing, the correct approach is to use the current palette, obtained from QWidget::palette(), and the required role, for example, QPalette::foreground(). Each role function returns a brush, which is normally what we want, but if we just need the color we can extract it from the brush, as we did in the paintEvent(). By default, the brushes returned are those appropriate to the widget's state, so we do not need to specify a color group.

The paintEvent() function finishes by drawing the image itself. The call to IconEditor::pixelRect() returns a QRect that defines the region to repaint. (Figure 5.4 illustrates how a rectangle is drawn.) As an easy optimization, we don't redraw pixels that fall outside this region.

Figure 5.4 Drawing a rectangle using

We call QPainter::fillRect() to draw a zoomed pixel. QPainter::fillRect() takes a QRect and a QBrush. By passing a QColor as the brush, we obtain a solid fill pattern. If the color isn't completely opaque (its alpha channel is less than 255), we draw a white background first.

The pixelRect() function returns a QRect suitable for QPainter::fillRect(). The mənj parameters are pixel coordinates in the QImage—not in the widget. If the zoom factor is 1, the two coordinate systems coincide exactly.

The QRect constructor has the syntax QRect( x, y, width, height), where ( x, y) is the position of the top-left corner of the rectangle and width x height is the size of the rectangle. If the zoom factor is 3 or more, we reduce the size of the rectangle by one pixel horizontally and vertically so that the fill does not draw over the grid lines.

When the user presses a mouse button, the system generates a "mouse press" event. By reimplementing QWidget::mousePressEvent(), we can respond to this event and set or clear the image pixel under the mouse cursor.

If the user pressed the left mouse button, we call the private function setImagePixel() ilə doğru as the second argument, telling it to set the pixel to the current pen color. If the user pressed the right mouse button, we also call setImagePixel(), but pass false to clear the pixel.

The mouseMoveEvent() handles "mouse move" events. By default, these events are generated only when the user is holding down a button. It is possible to change this behavior by calling QWidget::setMouseTracking(), but we don't need to do so for this example.

Just as pressing the left or right mouse button sets or clears a pixel, keeping it pressed and hovering over a pixel is also enough to set or clear a pixel. Since it's possible to hold more than one button pressed down at a time, the value returned by QMouseEvent::buttons() is a bitwise OR of the mouse buttons. We test whether a certain button is pressed down using the & operator, and if this is the case we call setImagePixel().

The setImagePixel() function is called from mousePressEvent()mouseMoveEvent() to set or clear a pixel. The pos parameter is the position of the mouse on the widget.

The first step is to convert the mouse position from widget coordinates to image coordinates. This is done by dividing the x()y() components of the mouse position by the zoom factor. Next, we check whether the point is within the correct range. The check is easily made using QImage::rect()QRect::contains() this effectively checks that mən is between 0 and image.width() - 1 and that j is between 0 and image.height() - 1.

Depending on the opaque parameter, we set or clear the pixel in the image. Clearing a pixel is really setting it to be transparent. We must convert the pen QColor to a 32-bit ARGB value for the QImage::setPixel() call. At the end, we call update() with a QRect of the area that needs to be repainted.

Now that we have reviewed the member functions, we will return to the Qt::WA_StaticContents attribute that we used in the constructor. This attribute tells Qt that the widget's content doesn't change when the widget is resized and that the content stays rooted to the widget's top-left corner. Qt uses this information to avoid needlessly repainting areas that are already shown when resizing the widget. This is illustrated by Figure 5.5.

Normally, when a widget is resized, Qt generates a paint event for the widget's entire visible area. But if the widget is created with the Qt::WA_StaticContents attribute, the paint event's region is restricted to the pixels that were not previously shown. This implies that if the widget is resized to a smaller size, no paint event is generated at all.

The IconEditor widget is now complete. Using the information and examples from earlier chapters, we could write code that uses the IconEditor as a window in its own right, as a central widget in a QMainWindow, as a child widget inside a layout, or as a child widget inside a QScrollArea. In the next section, we will see how to integrate it with Qt Designer.


Platform Plugins for Windowing Systems on Embedded Linux Devices

This is the X11 plugin used on regular desktop Linux platforms. In some embedded environments, that provide X and the necessary development files for xcb, this plugin functions just like it does on a regular PC desktop.

Qeyd: On some devices there is no EGL and OpenGL support available under X because the EGL implementation is not compatible with Xlib. In this case the XCB plugin is built without EGL support, meaning that Qt Quick 2 or other OpenGL-based applications does not work with this platform plugin. It can still be used however to run software-rendered applications (based on QWidget for example).

As a general rule, the usage of XCB on embedded devices is not advisable. Plugins like eglfs are likely to provide better performance, and hardware acceleration.

Wayland

Wayland is a light-weight windowing system or more precisely, it is a protocol for clients to talk to a display server.

The Qt Wayland module provides a wayland platform plugin that allows Qt application to connect to a Wayland compositor.

Qeyd: You may experience issues with touch screen input while using the Weston reference compositor. Refer to the Qt Wiki for further information.