Форум программистов, компьютерный форум, киберфорум
iamvic
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
Путевые заметки в процессе познания Python и PyQt/PySide.
Помни - только тег CODE не портит код добавлением пробела в начало пустой строки.

К вопросу о применении QtCore.QMetaObject. connectSlotsByName().

Запись от iamvic размещена 07.01.2022 в 19:04
Показов 2745 Комментарии 0
Метки pyqt5, python, python 3, qt5

QtCore.QMetaObject.connectSlotsByName() - штука, конечно, замечательная,
но несколько неоднозначная на мой взгляд. Надо поразмыслить потом на досуге.

Обычно-то, как действуем без использования QtCore.QMetaObject.connectSlotsByName()?
Все сигналы в своей прикладухе цепляем к слотам ручками, примерно как в этом примере:

Вариант A:
Python
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
78
79
80
81
82
83
84
85
86
87
88
89
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import sys
 
from PyQt5.QtWidgets import QApplication, QMainWindow
from PyQt5.QtWidgets import QStyleFactory
from PyQt5.QtWidgets import QAbstractItemView
from PyQt5.QtWidgets import QTableView
from PyQt5.QtGui import QStandardItem, QStandardItemModel
from PyQt5.QtCore import Qt, QMetaObject
from PyQt5.QtCore import QItemSelectionModel
 
class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.setGeometry(300, 200, 500, 400)
 
        w_view = QTableView(self)
        w_model = QStandardItemModel(self)
        w_model.setHorizontalHeaderLabels(['Деталь', 'Длина', 'Поставщик'])
 
        w_view.setModel(w_model)
        # в списке детей w_view появляется экземпляр QItemSelectionModel
 
        w_view.setSortingEnabled(True)
        w_view.setSelectionBehavior(QAbstractItemView.SelectRows)
        w_view.horizontalHeader().setStretchLastSection(True)
        w_view.setEditTriggers(QAbstractItemView.NoEditTriggers)
        w_view.setSelectionMode(QAbstractItemView.SingleSelection)
 
        w_view.activated.connect(self.on_tableview_activated)
        w_view.clicked.connect(self.on_tableview_clicked)
        w_view.doubleClicked.connect(self.on_tableview_doubleClicked)
        w_view.entered.connect(self.on_tableview_entered)
        w_view.pressed.connect(self.on_tableview_pressed)
 
        w_model.rowsInserted.connect(self.on_itemmodel_rowsInserted)
 
        w_select = w_view.findChild(QItemSelectionModel,
                                   '', Qt.FindDirectChildrenOnly)
        if w_select is not None:
            w_select.currentChanged.connect(self.on_selectmodel_currentChanged)
            w_select.selectionChanged.connect(self.on_selectmodel_selectionChanged)
 
        rows = [['Стойка', 200, 'Фабрика'],
                ['Штанга', 10, 'Завод'],
                ['Перекладина', 5, 'Мастерская']
               ]
        for row in rows:
            w_model.appendRow([QStandardItem(row[0]),
                               QStandardItem(str(row[1])),
                               QStandardItem(row[2])])
        w_view.selectRow(0)
 
        self.setCentralWidget(w_view)
 
    def on_tableview_activated(self, idx):
        print('activated({!s},{!s})'.format(idx.row(), idx.column()))
 
    def on_tableview_clicked(self, idx):
        print('clicked({!s},{!s})'.format(idx.row(), idx.column()))
 
    def on_tableview_doubleClicked(self, idx):
        print('doubleClicked({!s},{!s})'.format(idx.row(), idx.column()))
 
    def on_tableview_entered(self, idx):
        print('entered({!s},{!s})'.format(idx.row(), idx.column()))
 
    def on_tableview_pressed(self, idx):
        print('pressed({!s},{!s})'.format(idx.row(), idx.column()))
 
    def on_itemmodel_rowsInserted(self, p, first, last):
        print('rowsInserted({!s},{!s})'.format(first, last))
 
    def on_selectmodel_currentChanged(self, c_idx, p_idx):
        print('currentChanged({!s},{!s})<-({!s},{!s})'.format(
              c_idx.row(), c_idx.column(), p_idx.row(), p_idx.column()))
 
    def on_selectmodel_selectionChanged(self, s, d):
        print('selectionChanged({!s})'.format(s.indexes()[0].row()))
 
if __name__ == '__main__':
    app = QApplication(sys.argv)
 
    mwin = MainWindow()
    mwin.show()
 
    app.exec_()
    sys.exit()
Это всё, конечно, нудно и многословно, чревато ошибками и так далее.
А QtCore.QMetaObject.connectSlotsByName() предлагает снять эту нудную обязанность
с программиста, отяготив его всего лишь необходимостью присвоения объектам уникальных имён
и соблюдения правил именования слотов, принимающих сигналы на обработку, примерно так:

Вариант B:
Python
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
78
79
80
81
82
83
84
85
86
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import sys
 
from PyQt5.QtWidgets import QApplication, QMainWindow
from PyQt5.QtWidgets import QStyleFactory
from PyQt5.QtWidgets import QAbstractItemView
from PyQt5.QtWidgets import QTableView
from PyQt5.QtGui import QStandardItem, QStandardItemModel
from PyQt5.QtCore import Qt, QMetaObject
from PyQt5.QtCore import QItemSelectionModel
 
class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.setObjectName('mainwindow')
        self.setGeometry(300, 200, 500, 400)
 
        w_view = QTableView(self)
        w_view.setObjectName('tableview')
 
        w_model = QStandardItemModel(self)
        w_model.setObjectName('itemmodel')
        w_model.setHorizontalHeaderLabels(['Деталь', 'Длина', 'Поставщик'])
 
        w_view.setModel(w_model)
        # в списке детей w_view появляется экземпляр QItemSelectionModel
 
        w_select = w_view.findChild(QItemSelectionModel,
                                   '', Qt.FindDirectChildrenOnly)
        if w_select is not None:
            w_select.setObjectName('selectmodel')
 
        w_view.setSortingEnabled(True)
        w_view.setSelectionBehavior(QAbstractItemView.SelectRows)
        w_view.horizontalHeader().setStretchLastSection(True)
        w_view.setEditTriggers(QAbstractItemView.NoEditTriggers)
        w_view.setSelectionMode(QAbstractItemView.SingleSelection)
 
        QMetaObject.connectSlotsByName(self)
 
        rows = [['Стойка', 200, 'Фабрика'],
                ['Штанга', 10, 'Завод'],
                ['Перекладина', 5, 'Мастерская']
               ]
        for row in rows:
            w_model.appendRow([QStandardItem(row[0]),
                               QStandardItem(str(row[1])),
                               QStandardItem(row[2])])
        w_view.selectRow(0)
 
        self.setCentralWidget(w_view)
 
    def on_tableview_activated(self, idx):
        print('activated({!s},{!s})'.format(idx.row(), idx.column()))
 
    def on_tableview_clicked(self, idx):
        print('clicked({!s},{!s})'.format(idx.row(), idx.column()))
 
    def on_tableview_doubleClicked(self, idx):
        print('doubleClicked({!s},{!s})'.format(idx.row(), idx.column()))
 
    def on_tableview_entered(self, idx):
        print('entered({!s},{!s})'.format(idx.row(), idx.column()))
 
    def on_tableview_pressed(self, idx):
        print('pressed({!s},{!s})'.format(idx.row(), idx.column()))
 
    def on_itemmodel_rowsInserted(self, p, first, last):
        print('rowsInserted({!s},{!s})'.format(first, last))
 
    def on_selectmodel_currentChanged(self, c_idx, p_idx):
        print('currentChanged({!s},{!s})<-({!s},{!s})'.format(
              c_idx.row(), c_idx.column(), p_idx.row(), p_idx.column()))
 
    def on_selectmodel_selectionChanged(self, s, d):
        print('selectionChanged({!s})'.format(s.indexes()[0].row()))
 
if __name__ == '__main__':
    app = QApplication(sys.argv)
 
    mwin = MainWindow()
    mwin.show()
 
    app.exec_()
    sys.exit()
Объём текста, конечно, сокращается, но, на мой взгляд, несколько снижается наглядность.
Собственно говоря, на качество не влияет - дело привычки.

А для пользователей Qt Designer это должно, наверное, выглядеть примерно так:

Вариант C:
Python
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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import sys
 
from PyQt5.QtWidgets import QApplication, QMainWindow
from PyQt5.QtWidgets import QStyleFactory
from PyQt5.QtWidgets import QAbstractItemView
from PyQt5.QtWidgets import QTableView
from PyQt5.QtGui import QStandardItem, QStandardItemModel
from PyQt5.QtCore import Qt, QMetaObject
from PyQt5.QtCore import QItemSelectionModel
 
 
class MainWindow(QMainWindow):
    def on_tableview_activated(self, idx):
        print('activated({!s},{!s})'.format(idx.row(), idx.column()))
 
    def on_tableview_clicked(self, idx):
        print('clicked({!s},{!s})'.format(idx.row(), idx.column()))
 
    def on_tableview_doubleClicked(self, idx):
        print('doubleClicked({!s},{!s})'.format(idx.row(), idx.column()))
 
    def on_tableview_entered(self, idx):
        print('entered({!s},{!s})'.format(idx.row(), idx.column()))
 
    def on_tableview_pressed(self, idx):
        print('pressed({!s},{!s})'.format(idx.row(), idx.column()))
 
    def on_itemmodel_rowsInserted(self, p, first, last):
        print('rowsInserted({!s},{!s})'.format(first, last))
 
    def on_selectmodel_currentChanged(self, c_idx, p_idx):
        print('currentChanged({!s},{!s})<-({!s},{!s})'.format(
              c_idx.row(), c_idx.column(), p_idx.row(), p_idx.column()))
 
    def on_selectmodel_selectionChanged(self, s, d):
        print('selectionChanged({!s})'.format(s.indexes()[0].row()))
 
 
class Ui_Mwin(object):
    def setupUi(self, mwin):
        mwin.setObjectName('mainwindow')
        mwin.setGeometry(300, 200, 500, 400)
 
        w_view = QTableView(mwin)
        w_view.setObjectName('tableview')
 
        w_model = QStandardItemModel(mwin)
        w_model.setObjectName('itemmodel')
        w_model.setHorizontalHeaderLabels(['Деталь', 'Длина', 'Поставщик'])
 
        w_view.setModel(w_model)
        # в списке детей w_view появляется экземпляр QItemSelectionModel
 
        w_select = w_view.findChild(QItemSelectionModel,
                                   '', Qt.FindDirectChildrenOnly)
        if w_select is not None:
            w_select.setObjectName('selectmodel')
 
        w_view.setSortingEnabled(True)
        w_view.setSelectionBehavior(QAbstractItemView.SelectRows)
        w_view.horizontalHeader().setStretchLastSection(True)
        w_view.setEditTriggers(QAbstractItemView.NoEditTriggers)
        w_view.setSelectionMode(QAbstractItemView.SingleSelection)
 
        QMetaObject.connectSlotsByName(mwin)
 
        rows = [['Стойка', 200, 'Фабрика'],
                ['Штанга', 10, 'Завод'],
                ['Перекладина', 5, 'Мастерская']
               ]
        for row in rows:
            w_model.appendRow([QStandardItem(row[0]),
                               QStandardItem(str(row[1])),
                               QStandardItem(row[2])])
        w_view.selectRow(0)
 
        mwin.setCentralWidget(w_view)
 
 
if __name__ == '__main__':
    app = QApplication(sys.argv)
 
    mwin = MainWindow()
    ui = Ui_Mwin()
    ui.setupUi(mwin)
    mwin.show()
 
    app.exec_()
    sys.exit()
Впрочем, не настаиваю, инструментом не владею, пример сляпал ручками, хотя реалии вроде бы отражает.

Дополнение от 10.01.2022

Продолжая начатое, надо отметить, что созданные нами слоты не попадают в метаданные объекта,
хотя умный QMetaObject.connectSlotsByName() их всё-таки находит и цепляет к ним сигналы.
В этом легко убедиться, добавив сразу перед QMetaObject.connectSlotsByName() такой код:
Python
1
2
3
4
5
        meta = self.metaObject()
        print(meta.methodCount())
        for i in range(meta.methodCount()):
            print(meta.method(i).name().data().decode('utf-8'))
        print()
Протокольчик прилагается:.
Code
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
user@linux:~> python3 by_name_probe_b.py
37
destroyed
destroyed
objectNameChanged
deleteLater
_q_reregisterTimers
windowTitleChanged
windowIconChanged
windowIconTextChanged
customContextMenuRequested
setEnabled
setDisabled
setWindowModified
setWindowTitle
setStyleSheet
setFocus
update
repaint
setVisible
setHidden
show
hide
showMinimized
showMaximized
showFullScreen
showNormal
close
raise
lower
updateMicroFocus
_q_showIfNotHidden
grab
grab
iconSizeChanged
toolButtonStyleChanged
setAnimated
setDockNestingEnabled
setUnifiedTitleAndToolBarOnMac
 
rowsInserted(0,0)
rowsInserted(1,1)
rowsInserted(2,2)
currentChanged(0,0)<-(-1,-1)
selectionChanged(0)
Всё работает, сигналы приходят, а наших слотов в метаданных нет.
Исправить это упущение можно, украсив слоты декораторами:
Python
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
    @pyqtSlot(QModelIndex)
    def on_tableview_activated(self, idx):
        print('activated({!s},{!s})'.format(idx.row(), idx.column()))
 
    @pyqtSlot(QModelIndex)
    def on_tableview_clicked(self, idx):
        print('clicked({!s},{!s})'.format(idx.row(), idx.column()))
 
    @pyqtSlot(QModelIndex)
    def on_tableview_doubleClicked(self, idx):
        print('doubleClicked({!s},{!s})'.format(idx.row(), idx.column()))
 
    @pyqtSlot(QModelIndex)
    def on_tableview_entered(self, idx):
        print('entered({!s},{!s})'.format(idx.row(), idx.column()))
 
    @pyqtSlot(QModelIndex)
    def on_tableview_pressed(self, idx):
        print('pressed({!s},{!s})'.format(idx.row(), idx.column()))
 
    @pyqtSlot(QModelIndex, int, int)
    def on_itemmodel_rowsInserted(self, p, first, last):
        print('rowsInserted({!s},{!s})'.format(first, last))
 
    @pyqtSlot(QModelIndex, QModelIndex)
    def on_selectmodel_currentChanged(self, c_idx, p_idx):
        print('currentChanged({!s},{!s})<-({!s},{!s})'.format(
              c_idx.row(), c_idx.column(), p_idx.row(), p_idx.column()))
 
    @pyqtSlot(QItemSelection, QItemSelection)
    def on_selectmodel_selectionChanged(self, s, d):
        print('selectionChanged({!s})'.format(s.indexes()[0].row()))
А поскольку вся эта бодяга затевалась с целью отслеживания генерации сигналов
в режиме реального времени, то ввиду отсутствия гербовой (т.е. отладочного ядра Qt)
пришлось писать на простой, обильно уснащая код отладочной печатью .
И вариант B в этом случае принял вот такой окончательный вид:
Python
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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import sys, traceback
 
from PyQt5.QtWidgets import QApplication, QMainWindow
from PyQt5.QtWidgets import QAbstractItemView
from PyQt5.QtWidgets import QTableView
from PyQt5.QtGui import QStandardItem, QStandardItemModel
from PyQt5.QtCore import Qt, pyqtSlot
from PyQt5.QtCore import QMetaObject, QItemSelection, QModelIndex
from PyQt5.QtCore import QItemSelectionModel
 
 
def slot_trace_note(client):
    return '{!s} --> {!s} --> {!s}'.format(
           client.sender().objectName(),
           client.sender().metaObject().method(
           client.senderSignalIndex()).name().data().decode('utf-8'),
           traceback.extract_stack()[-2][2])
 
 
class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.setObjectName('mainwindow')
        self.setGeometry(300, 200, 500, 400)
 
        w_view = QTableView(self)
        w_view.setObjectName('tableview')
 
        w_model = QStandardItemModel(self)
        w_model.setObjectName('itemmodel')
        w_model.setHorizontalHeaderLabels(['Деталь', 'Длина', 'Поставщик'])
 
        w_view.setModel(w_model)
        # в списке детей w_view появляется экземпляр QItemSelectionModel
 
        w_select = w_view.findChild(QItemSelectionModel,
                                   '', Qt.FindDirectChildrenOnly)
        if w_select is not None:
            w_select.setObjectName('selectmodel')
 
        w_view.setSortingEnabled(True)
        w_view.setSelectionBehavior(QAbstractItemView.SelectRows)
        w_view.horizontalHeader().setStretchLastSection(True)
        w_view.setEditTriggers(QAbstractItemView.NoEditTriggers)
        w_view.setSelectionMode(QAbstractItemView.SingleSelection)
 
        meta = self.metaObject()
        print(meta.methodCount())
        for i in range(meta.methodCount()):
            print(meta.method(i).name().data().decode('utf-8'))
        print()
 
        QMetaObject.connectSlotsByName(self)
 
        rows = [['Стойка', 200, 'Фабрика'],
                ['Штанга', 10, 'Завод'],
                ['Перекладина', 5, 'Мастерская']
               ]
        for row in rows:
            w_model.appendRow([QStandardItem(row[0]),
                               QStandardItem(str(row[1])),
                               QStandardItem(row[2])])
        w_view.selectRow(0)
 
        self.setCentralWidget(w_view)
 
    @pyqtSlot(QModelIndex, name='on_tableview_activated')
    @pyqtSlot(QModelIndex, name='on_tableview_clicked')
    @pyqtSlot(QModelIndex, name='on_tableview_doubleClicked')
    @pyqtSlot(QModelIndex, name='on_tableview_entered')
    @pyqtSlot(QModelIndex, name='on_tableview_pressed')
    @pyqtSlot(QModelIndex)
    def on_tableview_signals(self, idx):
        print('{!s}({!s},{!s})'.format(slot_trace_note(self),
              idx.row(), idx.column()
              ))
 
    @pyqtSlot(QModelIndex, int, int)
    def on_itemmodel_rowsInserted(self, p, first, last):
        print('{!s}({!s},{!s})'.format(slot_trace_note(self),
              first, last
              ))
 
    @pyqtSlot(QModelIndex, QModelIndex)
    def on_selectmodel_currentChanged(self, c_idx, p_idx):
        print('{!s}({!s},{!s})<--({!s},{!s})'.format(slot_trace_note(self),
              c_idx.row(), c_idx.column(), p_idx.row(), p_idx.column()
              ))
 
    @pyqtSlot(QItemSelection, QItemSelection)
    def on_selectmodel_selectionChanged(self, s, d):
        print('{!s}({!s})'.format(slot_trace_note(self),
              s.indexes()[0].row()
              ))
 
 
if __name__ == '__main__':
    app = QApplication(sys.argv)
 
    mwin = MainWindow()
    mwin.show()
 
    app.exec_()
    sys.exit()
Ну, да, не без греха. Как получить имя выполняющегося слота средствами Qt разобраться
пока не сумел - пришлось traceback запользовать. Может быть кто знающий подскажет?

И вот такой симпатичный протокольчик по итогам:
Code
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
78
79
80
81
user@linux:~> python3 by_name_probe_b.py
46
destroyed
destroyed
objectNameChanged
deleteLater
_q_reregisterTimers
windowTitleChanged
windowIconChanged
windowIconTextChanged
customContextMenuRequested
setEnabled
setDisabled
setWindowModified
setWindowTitle
setStyleSheet
setFocus
update
repaint
setVisible
setHidden
show
hide
showMinimized
showMaximized
showFullScreen
showNormal
close
raise
lower
updateMicroFocus
_q_showIfNotHidden
grab
grab
iconSizeChanged
toolButtonStyleChanged
setAnimated
setDockNestingEnabled
setUnifiedTitleAndToolBarOnMac
on_selectmodel_currentChanged
on_itemmodel_rowsInserted
on_tableview_activated
on_tableview_clicked
on_tableview_doubleClicked
on_tableview_entered
on_tableview_pressed
on_tableview_signals
on_selectmodel_selectionChanged
 
itemmodel --> rowsInserted --> on_itemmodel_rowsInserted(0,0)
itemmodel --> rowsInserted --> on_itemmodel_rowsInserted(1,1)
itemmodel --> rowsInserted --> on_itemmodel_rowsInserted(2,2)
selectmodel --> currentChanged --> on_selectmodel_currentChanged(0,0)<--(-1,-1)
selectmodel --> selectionChanged --> on_selectmodel_selectionChanged(0)
selectmodel --> selectionChanged --> on_selectmodel_selectionChanged(1)
selectmodel --> currentChanged --> on_selectmodel_currentChanged(1,0)<--(0,0)
tableview --> activated --> on_tableview_signals(1,0)
selectmodel --> currentChanged --> on_selectmodel_currentChanged(2,0)<--(1,0)
selectmodel --> selectionChanged --> on_selectmodel_selectionChanged(2)
tableview --> pressed --> on_tableview_signals(2,0)
tableview --> clicked --> on_tableview_signals(2,0)
tableview --> activated --> on_tableview_signals(2,0)
selectmodel --> currentChanged --> on_selectmodel_currentChanged(1,0)<--(2,0)
selectmodel --> selectionChanged --> on_selectmodel_selectionChanged(1)
tableview --> pressed --> on_tableview_signals(1,0)
tableview --> clicked --> on_tableview_signals(1,0)
tableview --> activated --> on_tableview_signals(1,0)
tableview --> pressed --> on_tableview_signals(1,0)
tableview --> clicked --> on_tableview_signals(1,0)
tableview --> activated --> on_tableview_signals(1,0)
tableview --> doubleClicked --> on_tableview_signals(1,0)
tableview --> clicked --> on_tableview_signals(1,0)
tableview --> activated --> on_tableview_signals(1,0)
selectmodel --> currentChanged --> on_selectmodel_currentChanged(2,0)<--(1,0)
selectmodel --> selectionChanged --> on_selectmodel_selectionChanged(2)
tableview --> pressed --> on_tableview_signals(2,0)
tableview --> clicked --> on_tableview_signals(2,0)
tableview --> activated --> on_tableview_signals(2,0)
tableview --> doubleClicked --> on_tableview_signals(2,0)
tableview --> clicked --> on_tableview_signals(2,0)
tableview --> activated --> on_tableview_signals(2,0)
Нельзя не отметить, что поведение под Windows отличается от поведения под Linux
(возможно, в силу разницы в версиях PyQt).
Метки pyqt5, python, python 3, qt5
Размещено в Памятка
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Всего комментариев 0
Комментарии
 
Новые блоги и статьи
Hyper-V: Компьютер должен поддерживать доверенный платформенный модуль 2.0.
Maks 31.08.2026
При установке Windows 11 на виртуальную машину Hyper-V 2-го поколения вылезла такая ошибка: Решение: в параметрах виртуальной машины, в разделе "Безопасность" (Security) активировать флаг. . .
Архитектура биовида Стива в Майнкрафте: Зачем бонобо кубический каннибализм
anaschu 30.08.2026
Кубический Вагинокапитализм в Minecraft: Математический инвариант ОДУ и рок Стивов-бонобо Главная задача разработанной «Модели Всего» — наглядно продемонстрировать наличие системной «судьбы». . .
Оттачиваю умение писать js программы.
russiannick 30.08.2026
Проектом выходного дня стало написание Книги шифров Виженера. Итогом стала версия 200, синий туман. Синий туман назван так, потому что замораживает текст под собой. Нажатие синих кнопок управляют. . .
мат медиц модель 30. презентация проекта
anaschu 27.08.2026
хоп хоп хоп хидахоп, а я кладую))
Как у меня протекала болезнь
zorxor 27.08.2026
Здравствуйте, друзья! Эта запись блога предназначена именно для вас - для моих дорогих друзей, которые знали меня лично. Чтобы ответить на вопрос - а что же со мной произошло на самом деле? Я учился. . .
Нашел вот забавное видео о измерениях. Лучшее что я видел на эту тему
kumehtar 26.08.2026
ILETXiw9bMQ Основная суть и тезисы по измерениям: 0D (Нулевое измерение): точка, не имеющая длины, ширины, высоты или объема. Объект не может перемещаться в 0D. 1D (Первое измерение):. . .
[EasyBuilder Pro] Памятка по разработке для панелей Weintek
ФедосеевПавел 26.08.2026
Памятка по разработке для панелей Weintek ВВЕДЕНИЕ Ранее, при реализации проектов основное внимание уделял разработке управляющей программы для контроллера, а панели оператора доставалось время. . .
Модель по догадкам
anaschu 25.08.2026
Прошло две недели. Я уже рассказывал, как разговаривал с сотрудниками у сортировки и как понял, что главная ветка — не про приёмку, а про отбор. Но тогда я думал, что понял механику. На этой неделе я. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru