Как получить ссылку на элемент QTreeView?

Есть виджет QTreeView, состоящий из нескольких родительских и дочерних элементов (несколько уровней).

Не могу понять как вывести (к примеру в print) значение определенного элемента при его выборе в дереве?

ВАЖНО! Требуется получить не текст, не число, а именно ссылку на объект или сам объект, если это возможно, т.к. дочерние элементы (нижнего уровня) будут ссылаться на кортеж, содержащий текст, числа, переменные.

Т.е. будущее представление работы программы - следующее, в списке кликаю на элемент, на других виджетах появляется информация, хранимая в каком-либо кортеже.

mainwindow.py

from PyQt5 import QtCore, QtWidgets
from PyQt5.QtWidgets import QLabel, QApplication

from Modules.mainwidget import MainWidget
from Modules import styles


class MainWindow(QtWidgets.QMainWindow):

    def __init__(self, parent=None):
        QtWidgets.QMainWindow.__init__(self, parent, flags=QtCore.Qt.Window | QtCore.Qt.MSWindowsFixedSizeDialogHint |
                                       QtCore.Qt.FramelessWindowHint)
    self.setWindowTitle("Mechs alpha")
    self.setFixedSize(1000, 600)
    self.settings = QtCore.QSettings("mons", "Mechs")
    self.SGM = MainWidget()
    self.setCentralWidget(self.SGM)
    self.setStyleSheet(styles.window_style)
    self.SGM.setStyleSheet(styles.window_style)

    menubar = self.menuBar()  # главное меню
    menubar.setStyleSheet(styles.menu_style)
    menubar.setContextMenuPolicy(QtCore.Qt.PreventContextMenu)  
    file_menu = menubar.addMenu("File")
    settings_menu = menubar.addMenu("Settings")  
    about_menu = menubar.addMenu("Help")

    save_action = QtWidgets.QAction("Save Profile", self)
    file_menu.addAction(save_action)

    load_action = QtWidgets.QAction("Load Profile", self)
    file_menu.addAction(load_action)

    file_menu.addSeparator()  # разделитель в меню

    exit_action = QtWidgets.QAction("Quit", self)  
    exit_action.triggered.connect(self.close)
    file_menu.addAction(exit_action)

    about_action = about_menu.addAction("About", self.aboutInfo)

    toolbar = QtWidgets.QToolBar()
    self.addToolBar(toolbar) 
    toolbar.setMovable(False)
    toolbar.setFloatable(False)
    toolbar.setFixedHeight(30)
    toolbar.setContextMenuPolicy(QtCore.Qt.PreventContextMenu)

    open_implant = toolbar.addAction("Implant") 
    open_academy = toolbar.addAction("Academy") 
    open_research = toolbar.addAction("Research") 
    open_recruit = toolbar.addAction("Recruit") 
    do_screenshot = toolbar.addAction("Screenshot", self.take_screenshot)

    if self.settings.contains("X") and self.settings.contains("Y"): 
        self.move(self.settings.value("X"), self.settings.value("Y"))

    self.label = QLabel(self) 
    self.label.setText("Mechs alpha")
    self.label.setStyleSheet(styles.label_style)
    self.label.setGeometry(330, 1, 650, 20)

    quit_button = QtWidgets.QPushButton('X', self) 
    quit_button.setFixedSize(20, 20)
    quit_button.move(980, 0)
    quit_button.setFlat(True)
    quit_button.clicked.connect(self.close)

    minimize_button = QtWidgets.QPushButton('_', self) 
    minimize_button.setFixedSize(20, 20)
    minimize_button.move(960, 0)
    minimize_button.setFlat(True)
    minimize_button.clicked.connect(self.showMinimized)

    self.pressing = False

def take_screenshot(self):
    screen = QApplication.primaryScreen()
    winid = self.winId()
    pixmap = screen.grabWindow(winid, 240, 50, 750, 530)
    clipboard = QApplication.clipboard()
    clipboard.setPixmap(pixmap)

def closeEvent(self, evt):
    g = self.geometry()
    self.settings.setValue("X", g.left())
    self.settings.setValue("Y", g.top())

    result = QtWidgets.QMessageBox.question(self.SGM, "Closing confirmation",
                                            "Do you really want to close window?",
                                            QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No,
                                            QtWidgets.QMessageBox.No)
    if result == QtWidgets.QMessageBox.Yes:
        evt.accept()
        QtWidgets.QWidget.closeEvent(self.SGM, evt)
    else:
        evt.ignore()

def mousePressEvent(self, event):
    self.oldPos = event.globalPos()
    self.pressing = True

def mouseMoveEvent(self, event):
    if self.pressing:
        delta = QtCore.QPoint(event.globalPos() - self.oldPos)
        self.move(self.x() + delta.x(), self.y() + delta.y())
        self.oldPos = event.globalPos()

def mouseReleaseEvent(self, event):
    self.pressing = False

def aboutInfo(self):
    """Информация о программе"""
    QtWidgets.QMessageBox.about(self, "About app",
                                "<center>\"Mechs\" v0.0.1 alpha<br><br>"
                                "(c) 2020-2021")

mainwidget.py

from PyQt5 import QtCore, QtWidgets
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPixmap
from PyQt5.QtWidgets import QLabel

from Modules import shiplist, equipmentlist, styles, fitlist, ships_tuples


class MainWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
    QtWidgets.QWidget.__init__(self, parent)
    grid = QtWidgets.QGridLayout()
    grid.setSpacing(1)

    shiptree = QtWidgets.QVBoxLayout()
    frame_shiptree = QtWidgets.QFrame()
    frame_shiptree.setFixedSize(200, 250)
    frame_shiptree.setLayout(shiptree)
    grid.addWidget(frame_shiptree, 2, 1, 6, 1)
    shiptreebox = shiplist.ShipTreeView() 

    ship_tab = QtWidgets.QTabWidget()
    ship_tab.addTab(shiptreebox, "Ship") 
    ship_tab.addTab(fittreebox, "Fit") 
    shiptree.addWidget(ship_tab) 
    ship_tab.setCurrentIndex(0)
    ship_tab.setStyleSheet(styles.tab_style)

    self.setLayout(grid)

start.pyw Модуль старта приложения

from PyQt5 import QtGui, QtWidgets, QtCore
import sys
import time

from Modules.mainwindow import MainWindow
import styles

sys._excepthook = sys.excepthook

def my_exception_hook(exctype, value, traceback):
    """блок отлова исключения при закрытии программы"""
    print(exctype, value, traceback)
    sys._excepthook(exctype, value, traceback)
    sys.exit(1)

sys.excepthook = my_exception_hook

app = QtWidgets.QApplication(sys.argv)

app.processEvents()

window = MainWindow()
window.show()

try:
    sys.exit(app.exec_())
except:
    print('exiting')

shiplist.py

from PyQt5 import QtGui, QtWidgets

from Modules import styles
from PyQt5.QtWidgets import QPlainTextEdit, QHBoxLayout, QApplication, QWidget

mist_shiplist_name = QtGui.QStandardItem('Mist')
frost_shiplist_name = QtGui.QStandardItem('Frost')
glimmer_shiplist_name = QtGui.QStandardItem('Glimmer')

frigate_list = (mist_shiplist_name, frost_shiplist_name, glimmer_shiplist_name)


class ShipTreeView(QtWidgets.QTreeView):

def __init__(self, parent=None):
    QtWidgets.QTreeView.__init__(self, parent)
    self.ship_standard_item_model = QtGui.QStandardItemModel()
    self.setStyleSheet(styles.scrollbar_style)
    self.setAnimated(True)
    self.setIndentation(0)
    self.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)

    frigate_class = QtGui.QStandardItem('Frigate')
    self.ship_standard_item_model.appendRow([frigate_class])
    self.header().hide()
    self.setModel(self.ship_standard_item_model)

    t1_frigate_class = QtGui.QStandardItem('T1')
    frigate_class.appendRow(t1_frigate_class)
    for i in range(len(frigate_list)):
        stditem = QtGui.QStandardItem(frigate_list[i])
        t1_frigate_class.appendRow([stditem])
    self.header().hide()
    self.setModel(self.ship_standard_item_model)

    t2_frigate_class = QtGui.QStandardItem('T2')
    frigate_class.appendRow(t2_frigate_class)
    self.header().hide()
    self.setModel(self.ship_standard_item_model)

    t3_frigate_class = QtGui.QStandardItem('T3')
    frigate_class.appendRow(t3_frigate_class)
    self.header().hide()
    self.setModel(self.ship_standard_item_model)

def get_item(self, index):
    return self.ship_standard_item_model.itemFromIndex(index)

Сколько я ни пробовал - не могу врубиться в механику получения вообще чего либо при выборе элемента.


Ответы (2 шт):

Автор решения: gil9red

Элемент можно получить из модели по индексу. А индекс можно получить из сигнала clicked (для удобства добавил метод get_item)

В качестве примера добавил MyTreeView на окно с другим виджетом. Подключил сигнал clicked у дерева и сделал так, чтобы при клике выводился текст из дерева

Попробуйте:

from PyQt5 import QtGui, QtWidgets
from PyQt5.QtWidgets import QApplication, QWidget, QHBoxLayout, QPlainTextEdit
# from Modules import styles


first_item_name = QtGui.QStandardItem('first_item')
second_item_name = QtGui.QStandardItem('second_item')

first_list = (first_item_name, second_item_name)

second_list = ['11', '22', '33', '44', '55']


class MyTreeView(QtWidgets.QTreeView):
    def __init__(self, parent=None):
        QtWidgets.QTreeView.__init__(self, parent)
        self.standard_item_model = QtGui.QStandardItemModel()
        self.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)

        first_class = QtGui.QStandardItem('First')
        self.standard_item_model.appendRow([first_class])
        self.header().hide()
        self.setModel(self.standard_item_model)

        second_class = QtGui.QStandardItem('Second')
        self.standard_item_model.appendRow([second_class])
        self.header().hide()
        self.setModel(self.standard_item_model)

        t1_first_class = QtGui.QStandardItem('T1')
        first_class.appendRow(t1_first_class)
        for i in range(len(first_list)):
            stditem = QtGui.QStandardItem(first_list[i])
            t1_first_class.appendRow([stditem])
        self.header().hide()
        self.setModel(self.standard_item_model)

        t2_first_class = QtGui.QStandardItem('T2')
        first_class.appendRow(t2_first_class)
        self.header().hide()
        self.setModel(self.standard_item_model)

        t3_first_class = QtGui.QStandardItem('T3')
        first_class.appendRow(t3_first_class)
        self.header().hide()
        self.setModel(self.standard_item_model)

    def get_item(self, index):
        return self.standard_item_model.itemFromIndex(index)


class MainWindow(QWidget):
    def __init__(self):
        super().__init__()

        self.my_tree_view = MyTreeView()
        self.my_tree_view.clicked.connect(self.on_tree_view_click)

        self.text_edit = QPlainTextEdit()

        main_layout = QHBoxLayout()
        main_layout.addWidget(self.my_tree_view)
        main_layout.addWidget(self.text_edit)

        self.setLayout(main_layout)

    def on_tree_view_click(self, index):
        item = self.my_tree_view.get_item(index)
        self.text_edit.appendPlainText(item.text())


if __name__ == '__main__':
    app = QApplication([])

    mw = MainWindow()
    mw.show()

    app.exec()

Скриншот:

введите сюда описание изображения

→ Ссылка
Автор решения: S. Nick

Вам надо научиться создавать минимально-воспроизводимые примеры. В приведенном вами много лишних вещей, которые отвлекают и не хватает некоторого, чтобы запустить ваше приложение.

Я с трудностями запустил ваше приложение. Строки, которые выдавали ошибки, я просто закомментировал.

Я отметил для вас строки, в которые внес изменения, попробуйте.

import sys
# ? import time
# ? import styles
from PyQt5 import QtGui, QtWidgets, QtCore
from PyQt5.Qt import *


#?
class ShipTreeView(QtWidgets.QTreeView):
    def __init__(self, parent=None):
        QtWidgets.QTreeView.__init__(self, parent)
#+++ vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv         
        mist_shiplist_name = QtGui.QStandardItem('Mist')
        frost_shiplist_name = QtGui.QStandardItem('Frost')
        glimmer_shiplist_name = QtGui.QStandardItem('Glimmer')

        frigate_list = (mist_shiplist_name, frost_shiplist_name, glimmer_shiplist_name)
# +++ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^       
        
        self.ship_standard_item_model = QtGui.QStandardItemModel()
#        self.setStyleSheet(styles.scrollbar_style)
        self.setAnimated(True)
        self.setIndentation(0)
        self.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)

        frigate_class = QtGui.QStandardItem('Frigate')
        self.ship_standard_item_model.appendRow([frigate_class])
        self.header().hide()
        self.setModel(self.ship_standard_item_model)

        t1_frigate_class = QtGui.QStandardItem('T1')    
        frigate_class.appendRow(t1_frigate_class)
        #? frigate_list
        for i in range(len(frigate_list)):
            stditem = QtGui.QStandardItem(frigate_list[i])
            t1_frigate_class.appendRow([stditem])
            
        self.header().hide()
        self.setModel(self.ship_standard_item_model)

        t2_frigate_class = QtGui.QStandardItem('T2')
        frigate_class.appendRow(t2_frigate_class)
        self.header().hide()
        self.setModel(self.ship_standard_item_model)

        t3_frigate_class = QtGui.QStandardItem('T3')
        frigate_class.appendRow(t3_frigate_class)
        self.header().hide()
        self.setModel(self.ship_standard_item_model)

    def get_item(self, index):
        return self.ship_standard_item_model.itemFromIndex(index)


#? from Modules import shiplist, equipmentlist, styles, fitlist, ships_tuples
#from Modules.mainwidget import MainWidget
class MainWidget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        QtWidgets.QWidget.__init__(self, parent)
        
        grid = QtWidgets.QGridLayout()
        grid.setSpacing(1)

        shiptree = QtWidgets.QVBoxLayout()
        frame_shiptree = QtWidgets.QFrame()
        frame_shiptree.setFixedSize(200, 250)
        frame_shiptree.setLayout(shiptree)
        grid.addWidget(frame_shiptree, 2, 1, 6, 1)

#        shiptreebox = shiplist.ShipTreeView() 
        self.shiptreebox = ShipTreeView()                                      # +++ self.shiptreebox
        self.shiptreebox.clicked.connect(self.on_tree_view_click)              # +++

        ship_tab = QtWidgets.QTabWidget()
        ship_tab.addTab(self.shiptreebox, "Ship") 
# ???   fittreebox
#        ship_tab.addTab(fittreebox, "Fit") 
        shiptree.addWidget(ship_tab) 
        ship_tab.setCurrentIndex(0)
#        ship_tab.setStyleSheet(styles.tab_style)
        self.setLayout(grid)

# +++ vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
    def on_tree_view_click(self, index):
        item = self.shiptreebox.get_item(index)

        #Возвращает указатель на QStandardItem, связанный с данным индексом.
        pointerQStandardItem  = self.shiptreebox.ship_standard_item_model.itemFromIndex(index)
        print(f'Вы кликнули -> {item.text():>8}, --> pointerQStandardItem -> {pointerQStandardItem}')
# +++ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^


#from Modules.mainwindow import MainWindow
class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        QtWidgets.QMainWindow.__init__(self, parent, 
            flags=QtCore.Qt.Window | 
            QtCore.Qt.MSWindowsFixedSizeDialogHint |
            QtCore.Qt.FramelessWindowHint)
            
        self.setWindowTitle("Mechs alpha")
        self.setFixedSize(1000, 600)
        self.settings = QtCore.QSettings("mons", "Mechs")
        
        self.SGM = MainWidget()
        self.setCentralWidget(self.SGM)
        
#        self.setStyleSheet(styles.window_style)
#        self.SGM.setStyleSheet(styles.window_style)

        menubar = self.menuBar()  # главное меню
#        menubar.setStyleSheet(styles.menu_style)
        menubar.setContextMenuPolicy(QtCore.Qt.PreventContextMenu)  
        file_menu = menubar.addMenu("File")
        settings_menu = menubar.addMenu("Settings")  
        about_menu = menubar.addMenu("Help")

        save_action = QtWidgets.QAction("Save Profile", self)
        file_menu.addAction(save_action)

        load_action = QtWidgets.QAction("Load Profile", self)
        file_menu.addAction(load_action)

        file_menu.addSeparator()  # разделитель в меню

        exit_action = QtWidgets.QAction("Quit", self)  
        exit_action.triggered.connect(self.close)                   
        file_menu.addAction(exit_action)

        about_action = about_menu.addAction("About", self.aboutInfo)

        toolbar = QtWidgets.QToolBar()
        self.addToolBar(toolbar) 
        toolbar.setMovable(False)
        toolbar.setFloatable(False)
        toolbar.setFixedHeight(30)
        toolbar.setContextMenuPolicy(QtCore.Qt.PreventContextMenu)

        open_implant = toolbar.addAction("Implant") 
        open_academy = toolbar.addAction("Academy") 
        open_research = toolbar.addAction("Research") 
        open_recruit = toolbar.addAction("Recruit") 
        do_screenshot = toolbar.addAction("Screenshot", self.take_screenshot)
#?
        if self.settings.contains("X") and self.settings.contains("Y"): 
            self.move(self.settings.value("X"), self.settings.value("Y"))

        self.label = QLabel(self) 
        self.label.setText("Mechs alpha")
#        self.label.setStyleSheet(styles.label_style)
        self.label.setGeometry(330, 1, 650, 20)

        quit_button = QtWidgets.QPushButton('X', self) 
        quit_button.setFixedSize(20, 20)
        quit_button.move(980, 0)
        quit_button.setFlat(True)
        quit_button.clicked.connect(self.close)

        minimize_button = QtWidgets.QPushButton('_', self) 
        minimize_button.setFixedSize(20, 20)
        minimize_button.move(960, 0)
        minimize_button.setFlat(True)
        minimize_button.clicked.connect(self.showMinimized)

        self.pressing = False

    def take_screenshot(self):
        screen = QApplication.primaryScreen()
        winid = self.winId()
        pixmap = screen.grabWindow(winid, 240, 50, 750, 530)
        clipboard = QApplication.clipboard()
        clipboard.setPixmap(pixmap)

    def closeEvent(self, evt):
        g = self.geometry()
        self.settings.setValue("X", g.left())
        self.settings.setValue("Y", g.top())

        result = QtWidgets.QMessageBox.question(self.SGM, "Closing confirmation",
                                                "Do you really want to close window?",
                                                QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No,
                                                QtWidgets.QMessageBox.No)
        if result == QtWidgets.QMessageBox.Yes:
            evt.accept()
            QtWidgets.QWidget.closeEvent(self.SGM, evt)
        else:
            evt.ignore()

    def mousePressEvent(self, event):
        self.oldPos = event.globalPos()
        self.pressing = True

    def mouseMoveEvent(self, event):
        if self.pressing:
            delta = QtCore.QPoint(event.globalPos() - self.oldPos)
            self.move(self.x() + delta.x(), self.y() + delta.y())
            self.oldPos = event.globalPos()

    def mouseReleaseEvent(self, event):
        self.pressing = False

    def aboutInfo(self):
        """Информация о программе"""
        QtWidgets.QMessageBox.about(self, "About app",
                                    "<center>\"Mechs\" v0.0.1 alpha<br><br>"
                                    "(c) 2020-2021")


sys._excepthook = sys.excepthook
def my_exception_hook(exctype, value, traceback):
    """блок отлова исключения при закрытии программы"""
    print(exctype, value, traceback)
    sys._excepthook(exctype, value, traceback)
    sys.exit(1)
sys.excepthook = my_exception_hook


if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
#    app.processEvents()
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())
    
#try:
#    sys.exit(app.exec_())
#except:
#    print('exiting')

введите сюда описание изображения

→ Ссылка