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

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

Запись от iamvic размещена 07.01.2022 в 19:04
Показов 2665 Комментарии 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
Комментарии
 
Новые блоги и статьи
Рефакторинг программы уравнивания.
Massaraksh7 26.05.2026
Пример по предыдущей записи в блоге. Но, надо заметить, что, во-первых, там оптимизация не только математики, но и работы с базой данных, и с графами, а во-вторых, это ещё не всё.
Использование TThread в Lazarus для математических вычислений.
Massaraksh7 25.05.2026
Производя рефакторинг своих программ на предмет ускорения их работы, обратил внимание на такой аспект, как сокращение времени матвычислений. Дело в том, что приходится работать с большими матрицами. . .
Модель здравосохранения 18. Чем здоровее работник, тем быстрее выгорает
anaschu 24.05.2026
Имитационная модель корпоративного здравоохранения: что показывает математика Сегодня в модели рабочего коллектива на AnyLogic появились три новые механики — выгорание через накопленную усталость,. . .
Модель здравосохранения 17. Планы на выгорание
anaschu 23.05.2026
Вот конкретная схема реализации: В классе Работник добавить: накопленнаяУсталость — растёт каждый час работы, снижается в перерывы и болезни коэффициентПрезентеизма — снижает продуктивность. . .
Изменение цветов в палитре gif файла aka фавикона
russiannick 23.05.2026
Изменение цветов в палитре gif файла, юзаемого как фавиконка в составе html-файла, помещенная в base64, средствами нативного Java Script, навеянное сном в майский день. Для работы необходим браузер,. . .
Модель здравосохранения 16. Слишком хорошие и здоровые сотрудники уходят, недовольные зарплатой
anaschu 23.05.2026
Отладка увольнений и настройка производительности Сегодня во второй половине дня разобрались с механикой увольнений и настроили коэффициент сложности заданий. Вот что было сделано. . . .
Как я стал коммунистом))) Модель сохранения здоровья сотрудников, запись блога номер 15
anaschu 23.05.2026
Внезапно хорошее здоровье сотрудников не нужно капиталистам?))
Модель здравоСохранения 15. Как мы чинили AnyLogic модель рабочего коллектива: сочленение диаграммы состояний болезней и поломок в ресурспул
anaschu 23.05.2026
Как мы чинили AnyLogic модель рабочего коллектива Сегодня разобрались с пятью багами, из-за которых модель либо падала с ошибкой, либо давала совершенно бессмысленные результаты. Каждый баг был. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru