27 Aralık 2018 Perşembe

Qt'de Signal-Slot Kavramı

Qt Signal - Slot (İşaret - İşlev) Kavramı


Qt birden çok platformu destekleyen (cross-platform) masaüstü, gömülü sistem ve mobil ortamlar için grafiksel kullanıcı arayüzü geliştirmemizi sağlayan bir araçtır. Qt ile kullanıcı arayüzü geliştirmek için C++ programlama dili kullanılmaktadır. Qt'nin bana göre en önemli avantajı birçok işletim sisteminde (Windows, Linux, Mac) kullanılabiliyor olmasıdır (cross-platform özelliği). Bu özelliğe ek olarak ticari yazılımlar dışında hobi amaçlı yazılımlar için lisanslama sorunu yoktur. Ayrıca Qt ile arayüz geliştirmek Qt nin sunmuş olduğu sınıflar, fonksiyonlar ve signal-slot mekanizması sayesinde çok kolaydır. Diğer arayüz geliştirme ve programlama dillerinde olmayan signal-slot kavramı Qt de karşımıza çıkmaktadır. Bu yazıda
  • Signal-slot nedir ?
  • Signal-slot mekanizması nasıl çalışır ?
  • Öntanımlı (Default) işaretler (signal) nedir, nasıl kullanılır ?
  • Qt Designer ile signal-slot bağlantısı nasıl yapılır ?
  • Kod yazarak signal-slot bağlantısı nasıl yapılır ?
  • Kendimiz işaret (signal) tanımlayabilir miyiz ?
  • Signal-slot bağlantısı nasıl kaldırılır (iptal edilir)?
  • sorularına cevap bulacağız.


1. Signal - Slot Nedir ? Signal - Slot Mekanizması Nasıl Çalışır ?

Signal çok yabancı olmadığımız bir kelime Türkçeye de sinyal olarak geçmiştir. Slot kelimesinin ise yuva anlamı vardır. Aslında slot programlama dili açısından düşünüldüğünde fonksiyon olarak kullanılabilir. Fonksiyon da dilimizde yaygın olarak kullanılan bir kelime olmasına karşın Türkçe karşılığı işlev'dir. Signal-Slot yerine işaret-işlev diyebiliriz ancak bu kavram Qt'ye özgü bir kavram olduğu için signal-slot kavramından işaret-işlev olarak bahsedildiğinde kimse anlamayacaktır. Bu sebeple yazının geri kalan bölümünde signal-slot olarak orijinal hali ile kullanmayı planlıyorum.


Signal-slot kavramını yukarıda yer alan animasyon üzerinden anlatmaya çalışalım. Animasyonun sol üst köşesinde bir kullanıcı yer alıyor, sağ üst köşede ise bizim hazırlamış olduğumuz bir kullanıcı arayüzü olduğunu varsayalım. Kullanıcı, hazırlamış olduğumuz arayüz üzerinde bir eylemde bulunduğunda örneğin bir tuşa bastığında bir sinyal yayınlanır ve bu sinyal bir fonksiyona bağlı ise o fonksiyon çağrılır ve fonksiyon içerisinde yer alan işlem gerçekleştirilir. Arayüzü hazırlayan kişi arayüz elemanları ve fonksiyonlar arasında signal-slot bağlantıları yapar ve kullanıcı arayüz üzerinde bir işlem yaptığında ilgili fonksiyon çağrılır. Signal-slot mekanizması bu şekilde çalışır. Örneklerle birlikte bu kavramı daha iyi anlayacaksınız.

2. Öntanımlı (Default) İşaretler (Signals) Nedir? Öntanımlı İşaretler Nasıl Kullanılır ?

Öntanımlı (default) işaretler Qt tarafından önceden tanımlanmış parçacığa özgü işaretlerdir. Bu hazır işaretler çok rahatlıkla kullanılabilir. Yazının ilerleyen bölümlerinde öntanımlı işaretlerin kullanımını örneklerle daha iyi anlayacaksınız. Örneğin basılabilir tuşun (QPushButton) tıklandı (clicked), basıldı (pressed), bırakıldı (released) gibi öntanımlı işaretleri bulunmaktadır. Bu işaretleri fonksiyonlara bağladığınızda ve kullanıcı bu tuş üzerinde bir eylemde bulunduğunda ilgili fonksiyonlar çalıştırılır.


3. Qt Designer ile Signal - Slot Bağlantısı Nasıl Yapılır ?

Qt Designer ile signal-slot bağlantısı yapmak için öncelikle Qt Creator açılır ve yeni bir proje oluşturduktan sonra Qt Designer açılır. Qt Creator kullanımı, proje oluşturma, Qt Designer kullanımı hakkında bilgi edinmek için hazırlamış olduğum Qt Dersleri ücretsiz video serisini izleyebilirsiniz. Qt Creator'de Design Modunda yukarıda yer alan menüde bulunan Edit sekmesine tıklanır ve bu sekmede yer alan Edit Signals/Slots seçeneğine tıklanır.


Aynı işlemi F4 tuşuna basarak ya da aşağıdaki şekilde belirtilen tuşa basarak gerçekleştirebilirsiniz.


Signals-slots moduna geçmeden önce arayüz tasarımını tamamlamış olmalısınız ve arayüz üzerinde yer alan parçacıkların hangi işlevleri yapacağını belirlemiş olmanız gerekir. Signal-slot kavramını anlatabilmek için yatay kaydırma butonu (QHorizontalSlider) ve etiket (QLabel) parçacıklarından oluşan aşağıdaki tasarım yapıldı. Burada kaydırma butonunun konumu değiştirtirildiğinde o anki pozisyonunun değeri QLabel da gösterilecektir. Arayüz tasarımını tamamladık ve arayüzde yer alan parçacıkların ne iş yapacakları tanımlandıktan sonra yukarıda anlatıldığı gibi Signals/Slots moduna geçiş yapılır.


Signals-slots modunda iken Yatay Kaydırıcıya (HorizontalSlider) farenin sol tuşu ile tıklanır ve bu tuşa basılı tutularak etiketin (Label) üzerine getirilir ve burada tuş bırakılır. Tuşu bırakır bırakmaz Configure Connection adında yeni bir pencere açılacaktır. Bu pencerenin sol bölümünde yatay kaydırıcıya ait öntanımlı (default) işaretler bulunmaktadır. Biz burada değer değişti (valueChanged(int)) işaretini seçiyoruz. Bu işaret kaydırıcının değeri değiştiğinde işaret yayar. Biz bu işareti bir slot'a yani fonksiyona bağladığımızda kaydırıcının her değeri değiştiğinde bu fonksiyon çağrılacaktır.


İşaret seçimini yaptıktan sonra pencerenin sağ bölümü aktif hale gelir ve burada öntanımlı (default) slot'lar yani fonksiyonlar bulunmaktadır. Hem işaretler için hem de slot'lar için öntanımlı işaret ve slotları kullanabildiğimiz gibi kendi işaret ve fonksiyonlarımızı da Edit butonuna basarak tanımlayabiliriz. Biz burada etiket (Label) için setNum(int) fonksiyonunu seçiyoruz.





Yukarıda yer alan ekran görüntüsünde gördüğünüz gibi yatay kaydırıcının (HorizontalSlider) değeri değiştirildiğinde bu değer etikete (Label) yazdırılmaktadır. Burada basit bir şekilde herhangi bir kod yazmadan Qt Designer ile signal-slot bağlantısı gerçekleştirmiş olduk. Bu yöntem benim tercih ettiğim bir yöntem değil bu yüzden örnek sayısını arttırmadan ve daha fazla detaya girmeden konunun bu kadar yeterli olduğunu düşünüyorum. Kod yazarak signal-slot bağlantısının nasıl yapıldığını bir sonraki bölümde inceleyeceğiz.

4. Kod Yazarak Signal-Slot Bağlantısı Nasıl Yapılır ?

Bu bölümü Qt Designer'dan Go to slot özelliği ile kod yazarak signal-slot bağlantısı yapma ve connect() fonksiyonu ile signal-slot bağlantısı yapma olarak kendi içinde 2 alt başlık halinde inceleyeceğiz.

4.1. "Go to slot" ile Signal-Slot Bağlantısı

Qt Designer ile aşağıdaki ekran görüntüsünde yer alan bir buton (QPushButton) ve etiketten (QLabel) oluşan bir tasarım yapıyoruz. Bu tasarımda butona basınca etikette "butona basıldı" yazısı yazacak ve buton bırakıldığında "buton bırakıldı" yazacak.


Arayüz tasarımı ve arayüzde yer alan parçacıkların işlevleri tanımlandıktan sonra signal-slot bağlantısı için butonun üzerine farenin sağ tuşu ile tıklıyoruz ve açılan seçeneklerden Go to slot... seçeneğine tıklanır ve yeni bir pencere açılır.



Bu yeni pencerede QPushButton için öntanımlı (default) işaretler yer almaktadır. Burada "basıldı (pressed)" sinyalini seçip "OK" butonuna basıyoruz. Qt otomatik olarak bizim yerimize başlık dosyasında (mainwindow.h) ve kaynak dosyasında (mainwindow.cpp) slot yazmaktadır. Bizim tek yapmamız gereken kaynak dosyasında istediğimiz kodları yazmak.



Kaynak dosya içerisinde slot'un içerisinde etikete (QLabel) setText() fonksiyonu ile yazı yazdırıyoruz.


Aynı işlemleri "bırakıldı (released)" işareti için tekrar ediyoruz.





Qt Designer'da parçacığın üzerine farenin sağ tuşu ile tıklayarak "Go to slot" özelliğini kullandık ve signal-slot bağlantısının nasıl yapıldığını öğrendik. Bu yöntem öntanımlı (default) işaretler ile kullanılabilir ve benim arayüz geliştirirken sıklıkla kullandığım bir yöntem, sizin de kullanmanızı tavsiye ederim.

4.2. "connect()" fonksiyonu ile Signal-Slot Bağlantısı

Yazının başında kendimiz işaret (signal) tanımlayabilir miyiz diye sormuştuk, cevabımız evet. Qt'de öntanımlı (default) işaretler dışında istediğimiz işareti tanımlayabiliriz. Kendi tanımladığımız işareti slot'a bağlamak için connect() fonksiyonu kullanılır. Fonksiyonun kullanımı aşağıda belirtildiği gibidir.

connect( gönderen, SIGNAL(işaret_adı()), alıcı, SLOT(slot_adı()) )

  • Bir İşaret birden fazla Slot'a bağlanabilir


  • Birden fazla İşaret bir Slot'a bağlanabilir


  • Bir İşaret başka bir İşaret'e bağlanabilir


connect() fonksiyonunun kullanımını anlama ve yukarıda bahsedilen signal-slot özelliklerinin kullanımını öğrenebilmek için Qt Designer'da aşağıdaki ekran görüntüsünde yer alan tasarım yapılır.


mainwindow.h başlık dosyasında butona_basildi(), butona_basildi_2() ve butona_basildi_3() adında 3 tane işaret tanımlıyoruz. Bunlar Qt de varolan öntanımlı işaretler değil kendi tanımladığımız işaretler. Bir önceki bölümde Go to slot... özelliği ile tanımladığımız 2 tane slot'a ek olarak label_1_slot(), label_2_slot() ve label_3_slot() adında 3 tane slot tanımlıyoruz.


mainwindow.cpp kaynak dosyasında tanımladığımız işaretler ve slotları Yapıcı'da (constructor) connect() fonksiyonu ile birbirine bağlıyoruz. butona_basildi() işaretini label_1_slot(), label_2_slot() ve label_3_slot() adındaki slotlara bağlıyoruz ve bu bağlantı ile bir sinyalin birden fazla slot'a bağlanabildiğini görmüş olduk.


14 nolu satırda butona_basildi_2() işaretini label_1_slot() slotuna bağlıyoruz. Bu bağlantı ile birden fazla sinyalin aynı slot'a bağlanabildiğini görmüş olduk.

16 nolu satırda butona_basildi_3() işaretini butona_basildi() işaretine bağlıyoruz. Bu bağlantı ile bir sinyalin bir başka sinyale bağlanabildiğini görmüş olduk.

Kullanıcı arayüzde butona bastığında on_pushButton_pressed() slotu çalıştırılır. Bu slot içerisinde butona_basildi_3() işareti yayınlanır. İşaret yayınlamak için işaret adından önce emit ifadesi kullanılır. butona_basildi_3() işareti butona_basildi() işaretine bağlı olduğundan aynı zamanda butona_basildi() işareti de yayınlanmış olur. butona_basildi() işareti label_1_slot(), label_2_slot() ve label_3_slot() slotlarına bağlı olduğundan bu slotlar içerisinde yer alan kodlar çalıştırılır ve Etiketlere ilgili yazılar yazılır. Buton bırakıldığında on_pushButton_released() slotu içerisinde yer alan kodlar çalıştırılır ve etiketler üzerine hiçbir şey yazılmaz yani içerisinde önceden yazan yazılar silinir.

Son olarak belirtmem gereken konu işaretler ve slotlar parametre alabilir. Birbirlerine bağlanan işaret ve slotlar aynı sayıda ve tipte parametre alacak şekilde tanımlanmalıdır. Örneğin işarette 3 tane değişken tanımlanır ama slot'ta 2 tane değişken tanımlanırsa slot son parametreyi ihmal eder alamaz. Aynı türde olmayan değişkenler ise signal-slot arasındaki veri alışverişinde hataya sebep olacaktır.


5. Signal-slot bağlantısı nasıl kaldırılır (iptal edilir)?

Signal-slot bağlantısı yaparken connect() fonksiyonunu kullanarak yazmış olduğumuz ifadenin aynısını disconnect() ifadesiyle yazıyoruz.

disconnect( gönderen, SIGNAL(işaret_adı()), alıcı, SLOT(slot_adı()) )

Signal-slot bağlantısının iptal edilmesi çok sık kullanılan bir yöntem değildir ama arayüz geliştirirken ihtiyaç duyacağınız durumlar olabilir.


Signal-slot mekanizması kolay ve esnek kod yazmamızı sağlayan Qt nin sağlamış olduğu en önemli özelliklerden biridir. Bu yazıda signal-slot kavramını, signal-slot mekanizmasının nasıl çalıştığını, nasıl signal-slot bağlantısının yapıldığını elimden geldiğince anlatmaya çalıştım.

11 Kasım 2018 Pazar

PySide2 Qt Designer ile Matplotlib Kullanımı

PySide2 Qt Designer ile Matplotlib Kullanımı


Algoritma geliştirirken veya test ederken bir arayüz hazırlayarak onun üzerinde çalışmanın işleri kolaylaştırdığını, zaman kazandırdığını ve sonuçları daha iyi yorumlama fırsatı sunduğunu düşünüyorum. Qt arayüz hazırlamak için çok iyi bir programdır ve C++ programlama dili ile kullanılmaktadır. Python son yıllarda kullanım alanı çok hızlı bir şekilde genişleyen, öğrenmesi ve kod yazması kolay olan veri bilimi, yapay zeka vb. bir çok alanda kullanılan bir programlama dilidir. Hem Python programlama dilinin nimetlerinden yararlanmak hem de Qt ile arayüz geliştirmek istediğimizde yakın zamana kadar karşımıza sadece PyQt çıkmaktaydı, artık 2. bir seçeneğimiz var PySide2. Qt'nin resmi olarak geliştirdiği "Qt for Python : PySide2" yakın zamanda kullanıma sunuldu. PySide2 kurulum ve kullanımı için aşağıda linkleri verilen yazılarımı takip edebilirsiniz.
PySide2 Windows/Ubuntu Kurulumu
PySide2 ile Grafiksel Kullanıcı Arayüzü (GUI) Geliştirme


Bu yazıda Python programlama dilinde veri görselleştirme aşamasında en yaygın olarak kullanılan matplotlib paketinin Qt Designer ile tasarlanan PySide2 arayüzünde nasıl kullanılacağından bahsedeceğim. Matplotlib sadece Python 3 ile kullanılmaktadır. Aşağıdaki komutu çalıştırarak Matplotlib kurulumunu kolayca gerçekleştirebilirsiniz.




pip install matplotlib






PyQt5 ve Matplotlib kurulumuna ek olarak NumPy modülünü Matplotlib ile çizdirmek istediğimiz verileri dizi olarak tutmak için kurmanızı tavsiye ederim. Aşağıdaki komutu kullanarak kolayca kurulumu gerçekleştirebilirsiniz.




pip install numpy





İhtiyaç duyulan tüm modüllerin kurulumunu gerçekleştirmiş olduk. Qt Designer ile tasarım yapılan PySide2 arayüzünde matplotlib modülünün nasıl kullanılacağından bahsedeceğim.

1. Qt Designer ile Tasarım

Adım 1.1.
Qt Designer açılır. Qt Designer'ı, PySide2 kurulumunu yaptığınız Python klasöründe ../Python37/Lib/site-packages/PySide2 bulabilirsiniz.


Adım 1.2.
Qt Designer açıldığında daha önce hazırladığınız bir tasarımı açabilmenizi ya da yeni bir tasarım oluşturmanızı sağlamak amacıyla bir pencere çıkmaktadır. Burada temel olarak Dialog, Main Window ve Widget seçenekleri mevcut. Dialog kullanıcıdan bir seçenek seçmesini isteyen ya da kullanıcıyı bilgilendiren pencerelerdir. Main Window'da Widget penceresinden farklı olarak Menu (menubar) oluşturabilir ve arayüzün en alt bölümünde statusbar olarak adlandırılan bölümde kullanıcıya bilgilendirme mesajları sunabilirsiniz. Bu pencereden yeni bir tasarım için Widget seçiyoruz. Siz farklı bir tercihte bulunabilirsiniz.


Adım 1.3.
Tasarlamak istediğimiz arayüzün ekran görüntüsünü aşağıda bulabilirsiniz. Bir tane buton ve bir tane grafikten oluşan, butona basınca grafiği güncelleyen basit bir arayüz. Tasarımın detaylarını yazarak anlatmak çok zor olduğundan yazının sonuna bir video koyacağım oradan bakabilirsiniz.


Adım 1.4.
Push Button ve Widget nesneleri sürükle-bırak yöntemiyle arayüze bırakılır.


Adım 1.5.
Widget üzerinde matplotlib ile üreteceğimiz grafikleri göstereceğiz. Bunun için fare (mouse) Widget'ın üzerindeyken sağ tıklanır ve açılan seçeneklerden Promote to ... seçilir.


Adım 1.6.
Promote to ... seçildikten sonra aşağıda ekran görüntüsünde gösterildiği gibi yeni bir pencere açılacaktır. Bu pencerede Promoted class name: yazan bölüme matplotlib kısaltması olan Mpl ön eki kullanılarak MplWidget yazılır. Siz istediğiniz ismi verebilirsiniz. Buraya yazdığınızda Header file: bölümü otomatik sizin yazdığınız isme göre dolacaktır. Sonra Add butonuna basılır.


Yukarıda bahsedilen adımlar tamamlandıktan sonra Promote butonuna basılır.


Not.
Yukarıda bahsedilen adımlara ek olarak arayüzde bulunan (Promote işlemi yapılan) Widget'ın nesne adı (objectName) Promoted class name değişkeni ile aynı isim yapılır.


Adım 1.7.
Son olarak yapmış olduğumuz tasarımı Ctrl + S tuş kombinasyonu ile .ui uzantılı olarak kaydediyoruz. Bu işlemle birlikte tasarım aşamasında yapılacaklar bitti. Şimdi Python kodlarıyla tasarlamış olduğumuz arayüzü kullanma aşamasına geçebiliriz.

2. Python ile Qt Designer Tasarımını Kullanma


Projemizde toplam 2 tane dosya olacak :
  • main.py : Qt designer'da tasarladığımız arayüzü yükleyeceğimiz ve üzerinde işlemler yapacağımız ana Python dosyamız.
  • qt_designer.ui : Qt designer'da tasarımı yapılan arayüz dosyası.


Burada bir önceki yazımda PyQt5 için yapmış olduğumuz arayüzün aynısını PySide2 için yapacağız.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# ------------------ PySide2 - Qt Designer - Matplotlib ------------------
from PySide2.QtWidgets import*
from PySide2.QtUiTools import QUiLoader
from PySide2.QtCore import QFile

from matplotlib.backends.backend_qt5agg import (
        FigureCanvas, NavigationToolbar2QT as NavigationToolbar)

from matplotlib.figure import Figure

import numpy as np
import random

# ------------------ MplWidget ------------------
class MplWidget(QWidget):
    
    def __init__(self, parent = None):
        
        QWidget.__init__(self, parent)
        
        self.canvas = FigureCanvas(Figure())
        
        vertical_layout = QVBoxLayout()
        vertical_layout.addWidget(self.canvas)
        vertical_layout.addWidget(NavigationToolbar(self.canvas, self))
        
        self.canvas.axes = self.canvas.figure.add_subplot(111)
        self.setLayout(vertical_layout)    

# ------------------ MainWidget ------------------
class MainWidget(QWidget):
    
    def __init__(self):
        
        QWidget.__init__(self)

        designer_file = QFile("qt_designer.ui")
        designer_file.open(QFile.ReadOnly)

        loader = QUiLoader()
        loader.registerCustomWidget(MplWidget)
        self.ui = loader.load(designer_file, self)

        designer_file.close()

        self.ui.pushButton_generate_random_signal.clicked.connect(self.update_graph)

        self.setWindowTitle("PySide2 & Matplotlib Example GUI")

        grid_layout = QGridLayout()
        grid_layout.addWidget(self.ui)
        self.setLayout(grid_layout)


    def update_graph(self):
        
        fs = 500
        f = random.randint(1, 100)
        ts = 1/fs
        length_of_signal = 100
        t = np.linspace(0,1,length_of_signal)
        
        cosinus_signal = np.cos(2*np.pi*f*t)
        sinus_signal = np.sin(2*np.pi*f*t)

        self.ui.MplWidget.canvas.axes.clear()
        self.ui.MplWidget.canvas.axes.plot(t, cosinus_signal)
        self.ui.MplWidget.canvas.axes.plot(t, sinus_signal)
        self.ui.MplWidget.canvas.axes.legend(('cosinus', 'sinus'),loc='upper right')
        self.ui.MplWidget.canvas.axes.set_title('Cosinus - Sinus Signals')
        self.ui.MplWidget.canvas.draw()
        

app = QApplication([])
window = MainWidget()
window.show()
app.exec_()

Adım 2.1.
Yukarıda yer alan kodları 4 parça halinde anlatacağım. İlk bölümde (2-12 nolu satırlar) ihtiyaç duyulan paketler koda dahil edilir.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# ------------------ PySide2 - Qt Designer - Matplotlib ------------------
from PySide2.QtWidgets import*
from PySide2.QtUiTools import QUiLoader
from PySide2.QtCore import QFile

from matplotlib.backends.backend_qt5agg import (
        FigureCanvas, NavigationToolbar2QT as NavigationToolbar)

from matplotlib.figure import Figure

import numpy as np
import random

2 nolu satırda QtWidgets sınıfına ait tüm bileşenler kod içerisinde kullanmak için eklenir.
3 ve 4 nolu satırlarda Designer tasarım dosyasını yüklemek için kullandığımız QUiLoader ve QFile modüllerini kodumuza ekliyoruz.
6 nolu satırda Matplotlib modülünden FigureCanvas kodumuza eklenir.
Matplotlib 3 farklı katmandan oluşur ve en alt katmanda Backend, bir üst katmanda Artist ve en üst katmanda Scripting katmanı bulunmaktadır. Matplotlib modlünün yapısı hakkında detaylı bilgiye buradan ulaşabilirsiniz.
Backend katmanında bulunan FigureCanvas resim çizmek için ihtiyaç duyduğumuz kağıt (tuval) gibi düşünülebilir. FigureCanvas Matplotlib sınıfı olmasının yanında aynı zamanda bir QWidget sınıfıdır.
Artist katmanında Matplotlib de gördüğümüz başlık, grafik, x-y ekseni, etiketler vb. bileşenler yer almaktadır.
Script (pyplot) katmanı Matplotlib modülünün kolay kullanımını sağlayan en üst katmandır.
7 nolu satırda grafik üzerinde işlem yapabilmek için Matplotlib modülünden NavigationToolBar2QT koda dahil edilir.
9 nolu satırda Matplotlib modülünden Figure sınıfı kodumuza eklenir.
Aslında Matplotlib içerisinde PySide2 için tanımlanmış fonksiyonlar, sınıflar yok. Yukarıda yer alan kodlarda gördüğünüz gibi PyQt5 için var olan sınıf ve fonksiyonlar PySide2 için kullanılacaktır.
11 nolu satırda NumPy paketi matematiksel işlemler ve dizi işlemlerinde kullanmak için eklenmiştir.
12 nolu satırda Python kurulumu ile birlikte gelen random paketi rastgele sayı üretmek için koda eklenmiştir.

Adım 2.2.
İkinci bölümde (14-28 nolu satırlar) MplWidget sınıfı tanımlanmıştır. Qt designer'da Promote işlemi yapılan widget ile aynı ismi taşıdığına dikkat ediniz. Burada Matplotlib'in widget'ta kullanılmasını sağlayan işlemler yapılır.

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# ------------------ MplWidget ------------------
class MplWidget(QWidget):
    
    def __init__(self, parent = None):
        
        QWidget.__init__(self, parent)
        
        self.canvas = FigureCanvas(Figure())
        
        vertical_layout = QVBoxLayout()
        vertical_layout.addWidget(self.canvas)
        vertical_layout.addWidget(NavigationToolbar(self.canvas, self))

        self.canvas.axes = self.canvas.figure.add_subplot(111)
        self.setLayout(vertical_layout)

15-19 nolu satırlar her sınıfta bulunması gereken daha önce açıkladığım kısımlar olduğu için burada tekrar etmeyeceğim.
21 nolu satırda FigureCanvas sınıfından yeni bir nesne tanımlanmaktadır ve nesne adı (object name) "canvas" olarak tanımlanmıştır ve sınıf dışında bu etikete ulaşmamız gerekeceğinden bu parçacık self ifadesine atanmıştır.
23 nolu satırda dikey yerleşim düzeni ( QVBoxLayout ) tanımlıyoruz ve 24 nolu satırda addWidget fonksiyonunu kullanarak oluşturduğumuz FigureCanvas nesnesini bu dikey yerleşim planı içerisine ekliyoruz. 25 nolu satırda ise matplotlib paketinde yer alan NavigationToolBar2QT dikey yerleşim planı içerisine eklenir. Qt'de dikey yerleşim düzeninden ( QVBoxLayout ) farklı olarak Yatay yerleşim düzeni ( QHBoxLayout ) ve Izgara yerleşim düzeni ( QGridLayout ) bulunmaktadır.
27 nolu satırda oluşturduğumuz tuvale (FigureCanvas) yeni bir Axes tanımlıyoruz. Bu işlem için add_subplot fonksiyonunu kullanıyoruz.
28 nolu satırda oluşturduğumuz dikey yerleşim düzenini sınıfımızın (oluşturacağımız arayüzün) yerleşim düzeni olmasını sağlamak için setLayout fonksiyonuyla tanımlıyoruz. Bu satırla birlikte MplWidget sınıfına ait kodlarının açıklaması bitmiştir.

Adım 2.3.
Üçüncü bölümde (30-71 nolu satırlar) MainWidget ana sınıf tanımlanmıştır. Burada Qt Designer ile yapılan tasarım; içerisinde yer alan bileşenlere ulaşmak, üzerinde işlem yapabilmek için yüklenecektir.

30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# ------------------ MainWidget ------------------
class MainWidget(QWidget):
    
    def __init__(self):
        
        QWidget.__init__(self)

        designer_file = QFile("qt_designer.ui")
        designer_file.open(QFile.ReadOnly)

        loader = QUiLoader()
        loader.registerCustomWidget(MplWidget)
        self.ui = loader.load(designer_file, self)

        designer_file.close()

        self.ui.pushButton_generate_random_signal.clicked.connect(self.update_graph)

        self.setWindowTitle("PySide2 & Matplotlib Example GUI")

        grid_layout = QGridLayout()
        grid_layout.addWidget(self.ui)
        self.setLayout(grid_layout)


    def update_graph(self):
        
        fs = 500
        f = random.randint(1, 100)
        ts = 1/fs
        length_of_signal = 100
        t = np.linspace(0,1,length_of_signal)
        
        cosinus_signal = np.cos(2*np.pi*f*t)
        sinus_signal = np.sin(2*np.pi*f*t)

        self.ui.MplWidget.canvas.axes.clear()
        self.ui.MplWidget.canvas.axes.plot(t, cosinus_signal)
        self.ui.MplWidget.canvas.axes.plot(t, sinus_signal)
        self.ui.MplWidget.canvas.axes.legend(('cosinus', 'sinus'),loc='upper right')
        self.ui.MplWidget.canvas.axes.set_title('Cosinus - Sinus Signals')
        self.ui.MplWidget.canvas.draw()

31-35 nolu satırlar her sınıfta bulunması gereken daha önce açıkladığım kısımlar olduğu için burada tekrar etmeyeceğim.
37 ve 38 nolu satırlarda tasarım dosyasını (qt_designer.ui) okuyoruz.
40 nolu satırda QUiLoader sınıfından bir nesne tanımlıyoruz.
41 nolu satırda registerCustomWidget fonksiyonuyla Promote işlemi yaptığımız ve yukarıda MplWidget sınıfıyla tanımladığımız widget'ı kullanabilmemiz için bu fonksiyonu kullanmamız gerekir.
42 nolu satırda load fonskiyonuyla tasarım yüklenir ve self.ui değişkenine atanır. Tasarımla oluşturulan parçacıklara bu değişkeni kullanarak ulaşacağız.
44 nolu satırda yüklenen tasarım dosyası kapanır.
46 nolu satırda Qt Designer'da tanımladığımız butonun clicked sinyaline update_graph fonksiyonunu (slot) bağlıyoruz. Signal-slot bağlantısı için önceki yazıma bakabilirsiniz.
48 nolu satırda arayüz penceresine setWindowTitle fonksiyonu ile isim veriyoruz.
50-52 nolu satırlar hazırladığımız arayüzü farklı boyutlarda kullanmamızı sağlayacaktır.


55-71 nolu satırlar arası butona bağlanan update_graph fonksiyonu (slot) yazılmıştır. Kullanıcı butona her bastığında kodumuz bu fonksiyonu çalıştıracaktır.
57-64 satırlar arası, NumPy ve random paketlerindeki fonksiyonlar kullanılarak rastgele frekanslarda sinus ve cosinus fonksiyonları üretilmektedir.
66 nolu satırda grafiğe yeni bir çizim yapmadan önce önceki çizimler silinir. Bu işlemi yapmazsak grafikleri üst üste çizer.
67-68 nolu satırlarda üretilen cosinus ve sinus fonksiyonları çizdirilmektedir.
69 nolu satırda çizdirdiğimiz grafikleri ayırt etmek için legend eklenir.
70 nolu satırda grafiğe başlık eklenir.
71 nolu satırda grafiğimiz çizdirilir.

Adım 2.4.
Son bölümde (74-77 nolu satırlar) arayüzün gösterilmesi ve çalıştırılması işlemleri yapılır.

74
75
76
77
app = QApplication([])
window = MainWidget()
window.show()
app.exec_()

74 nolu satırda QApplication sınıfından app adında bir nesne tanımlıyoruz.
75 nolu satırda MainWidget adında tanımladığımız sınıftan window adında bir nesne oluşturuyoruz.
76 nolu satırda show() fonksiyonunu kullanarak arayüz için oluşturduğumuz pencereyi gösteriyoruz
77 nolu satırda QApplication sınıfının exec_() fonksiyonu ile sonsuz bir döngü oluşturulur. Bu ifade ile kullanıcının arayüzü kullanarak fare ve klavye ile yapmış olduğu tüm işlemler yakalanarak komutlar yerine getirilir.


Qt Designer ile tasarlanan arayüzde Matplotlib paketini kullanarak nasıl grafik çizdireceğimizi öğrenmiş olduk. Değinmediğimiz birçok özellik olabilir, ancak bunu bir başlagıç olarak kabul ederek daha iyi daha güzel arayüzleri kendi çalışmalarınız için hazırlayabilirsiniz.