pyqt - перетаскивание строк в таблице не позволяет перетаскивать изображения и виджеты в ячейки - PullRequest
0 голосов
/ 07 августа 2020

Я использовал класс из stackoverflow, который применяет функцию перетаскивания к строкам таблицы, но не сохраняет изображения от удаления из ячеек при перетаскивании любой строки, мне нужна помощь, чтобы выяснить, как исправить код, чтобы сделать это жоп! код всего проекта с базой данных: используемая база данных: https://gofile.io/d/c0srQ0

from PyQt5 import QtWidgets, QtGui, QtCore

from PyQt5.QtGui import *
from PyQt5.QtCore import *

from PyQt5.QtWidgets import (QApplication, QComboBox, QDialog,
QDialogButtonBox, QFormLayout, QGridLayout, QGroupBox, QHBoxLayout,
QLabel, QLineEdit, QMenu, QMenuBar, QPushButton, QSpinBox, QTextEdit,
QVBoxLayout, QStyledItemDelegate, QCheckBox, QTableWidgetItem, QAbstractItemView, QTableWidget)

import sqlite3
import random
import ast
#import qdarkstyle

class Main(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.cashed = []
        self.setWindowTitle('Arabic Math Project')
        self.setContentsMargins(20,20,20,20)
        # create table:
        #Options()
        #self.setStyleSheet(qdarkstyle.load_stylesheet())
        layout = QVBoxLayout()

        self.searchBar = QtWidgets.QLineEdit()
        self.searchBar.setAlignment(QtCore.Qt.AlignCenter)
        self.searchBar.setPlaceholderText("search")
        self.searchBar.textChanged.connect(self.startSearchThreading) #editingFinished()
        #self.table = QtWidgets.QTableWidget()

        self.table = TableWidgetDragRows()
     
        conn = sqlite3.connect("math.db")
        conn.text_factory = bytes
        self.cur = conn.cursor()


        data = self.cur.execute("select * from problems;").fetchall();conn.close()
        self.dims = (lambda x: (len(x), len(x[0])))(data) #(rows number, col number)

        [self.table.insertRow(i) for i in [i for i in range(self.dims[0])]]
        [self.table.insertColumn(i) for i in [i for i in range(self.dims[1]+1)]]

        #changing h-header names .
        self.table.setHorizontalHeaderLabels(["Unique", "Image", "Test", "Year", "Lesson", "Page","Comment", "Options", "Options-advanced"])

        for c in range(self.dims[1]):
            for r in range(self.dims[0]):
                if c!=1:self.table.setItem(r, c, QtWidgets.QTableWidgetItem(data[r][c].decode("utf-8"))) 
                else:self.table.setCellWidget(r, c, self.getImage(data[r][c]))

        for r in range(self.dims[0]):self.table.setCellWidget(r, self.dims[1], Options(ops=[data[r][self.dims[1]-1].decode("utf-8")], row=data[r]))



        #table h & v  auto - resizing . 
        header = self.table.horizontalHeader()
        header.setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)
        header.setSectionResizeMode(2, QtWidgets.QHeaderView.Interactive)
        header.setSectionResizeMode(7, QtWidgets.QHeaderView.Interactive)
        headerv = self.table.verticalHeader()
        headerv.setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)

        #hide the options column cuz it doesn't concern user to see it.
        self.table.setColumnHidden(7, True)

        #layout setting up.
        layout.addWidget(self.searchBar)
        layout.addWidget(self.table)
        self.setLayout(layout)

    def getImage(self, image):
        imageLabel = ScaledPixmapLabel()
        pixmap = QtGui.QPixmap()
        pixmap.loadFromData(image, "jpg")
        imageLabel.setPixmap(pixmap)
        return imageLabel

    def startSearchThreading(self):
        self.table.setRowCount(0)
        self.update = updateTable(data= self.searchBar.text())
        self.update.new_signal.connect(self.Search)
        self.update.start()

    def create(self):
        self.createFormGroupBox()
        return self.formGroupBox

    @QtCore.pyqtSlot(int, int, bytes, bool, bytes)
    def Search(self, r, c, d, newRowOrder, ops):
        if newRowOrder:self.table.insertRow(self.table.rowCount()) # create new row.        
        if c!=1:self.table.setItem(r, c, QtWidgets.QTableWidgetItem(d.decode("utf-8"))) 
        else:self.table.setCellWidget(r, c, self.getImage(d))
        self.cashed.append(d)
        if c ==self.dims[1]-1:
            self.table.setCellWidget(r, self.dims[1], Options(ops=[ops.decode("utf-8")], row=self.cashed))
            self.cashed = []


class updateTable(QtCore.QThread):
    def __init__(self, parent=None, data=True):
        super(QtCore.QThread, self).__init__()
        self.data = data

    new_signal = QtCore.pyqtSignal(int, int, bytes, bool, bytes)

    def run(self):
        currRow = 0
        conn = sqlite3.connect("math.db")
        conn.text_factory = bytes
        self.cur = conn.cursor()
        searched = self.cur.execute(" SELECT * FROM problems WHERE text LIKE ('%' || ? || '%') ", (self.data,)).fetchall()
        dims = (lambda x: (len(x), len(x[0])))(searched) if searched!=[] else (0, 0)
        for r in range(dims[0]):
            for c in range(dims[1]):
                self.new_signal.emit(r, c, searched[r][c], True if c==0 else False, searched[r][dims[1]-1])



class ScaledPixmapLabel(QtWidgets.QLabel):
    def __init__(self):
        super().__init__()
        self.setScaledContents(True)

    def paintEvent(self, event):
        if self.pixmap():
            pm = self.pixmap()
            originalRatio = pm.width() / pm.height()
            currentRatio = self.width() / self.height()
            if originalRatio != currentRatio:
                qp = QtGui.QPainter(self)
                pm = self.pixmap().scaled(self.size(), QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation)
                rect = QtCore.QRect(0, 0, pm.width(), pm.height())
                rect.moveCenter(self.rect().center())
                qp.drawPixmap(rect, pm)
                return
        super().paintEvent(event)

class Options(QtWidgets.QWidget):
    def __init__(self, parent=None,row=[], ops=[]):
        super(Options, self).__init__(parent)
        self.i = random.randint(1, 100)
        self.row = [j.decode("utf-8") if i!=1 else "image" for i,j in enumerate(row)]
        self.formLayout = QFormLayout()
        self.setStyleSheet(open("styles.css").read())
        ops = ast.literal_eval(ops[0]) if ops!=[] else {}
        for i,j in ops.items():
            widget = {"lineedit": QLineEdit(), "combobox": QComboBox(), "spinbox": QSpinBox(), "checkbox": QCheckBox()}

            title  = j.get("title", "")
            combos = j.get("combos", [])

            if i == "lineedit":widget[i].setText(j.get("default", ""))
            elif i == "combobox":widget[i].addItems(combos)
            elif i == "checkbox":
                widget[i].setCheckState((lambda x: {1:2, 2:2, 0:0}[x])(j.get("default", 0)))
                widget[i].setText(j.get("text", ""))
            elif i == "spinbox":
                widget[i].setMaximum(j.get("max", 100))
                widget[i].setMinimum(j.get("min", 0))

            self.formLayout.addRow(QLabel(title), widget[i])

        self.btn = QtWidgets.QPushButton("Submit")
        self.btn.clicked.connect(self.do)
        self.formLayout.addWidget(self.btn)
        self.formLayout.setFormAlignment(QtCore.Qt.AlignVCenter)
        self.setLayout(self.formLayout)

    def do(self):
        #[STOPED HERE]
        heads, tails = [], []
        for i in range(self.formLayout.count()):
            w = self.formLayout.itemAt(i).widget()
            if i%2==0:heads.append(w.text())
            elif isinstance(w, QLineEdit):tails.append(w.text())
            elif isinstance(w, QComboBox):tails.append(w.currentText())
            elif isinstance(w, QSpinBox):tails.append(w.value())
            elif isinstance(w, QCheckBox):tails.append(w.checkState())

        values = {i:j for i,j in zip(heads, tails)}
        print(self.row[:-1]+[values])

class TableWidgetDragRows(QTableWidget):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.setDragEnabled(True)
        self.setAcceptDrops(True)
        self.viewport().setAcceptDrops(True)
        self.setDragDropOverwriteMode(False)
        self.setDropIndicatorShown(True)

        self.setSelectionMode(QAbstractItemView.ExtendedSelection)
        #self.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.setDragDropMode(QAbstractItemView.InternalMove)

    def dropEvent(self, event: QDropEvent):
        if not event.isAccepted() and event.source() == self:
            drop_row = self.drop_on(event)

            rows = sorted(set(item.row() for item in self.selectedItems()))
            print(rows)
            rows_to_move = [[QTableWidgetItem(self.item(row_index, column_index)) for column_index in range(self.columnCount())]
                            for row_index in rows]
            for row_index in reversed(rows):
                self.removeRow(row_index)
                if row_index < drop_row:
                    drop_row -= 1

            for row_index, data in enumerate(rows_to_move):
                row_index += drop_row
                self.insertRow(row_index)
                for column_index, column_data in enumerate(data):
                    self.setItem(row_index, column_index, column_data)
            event.accept()
            for row_index in range(len(rows_to_move)):
                self.item(drop_row + row_index, 0).setSelected(True)
                self.item(drop_row + row_index, 1).setSelected(True)
        super().dropEvent(event)

    def drop_on(self, event):
        index = self.indexAt(event.pos())
        if not index.isValid():
            return self.rowCount()

        return index.row() + 1 if self.is_below(event.pos(), index) else index.row()

    def is_below(self, pos, index):
        rect = self.visualRect(index)
        margin = 2
        if pos.y() - rect.top() < margin:
            return False
        elif rect.bottom() - pos.y() < margin:
            return True
        # noinspection PyTypeChecker
        return rect.contains(pos, True) and not (int(self.model().flags(index)) & Qt.ItemIsDropEnabled) and pos.y() >= rect.center().y()


if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    main = Main()
    main.resize(600,600)
    main.show()
    app.exec_()

1 Ответ

0 голосов
/ 07 августа 2020

Вы устанавливаете изображения, используя QLabels, установленные как виджеты ячеек. Установка виджетов ячеек - это только функция, используемая пользовательским интерфейсом таблицы: она полностью не связана с базовой моделью, и элементы QTableWidgetItem также ничего о них не знают. Итак, вам полностью решать, есть ли в ячейке набор виджетов, и переместить этот виджет соответствующим образом. каждый раз, потому что, когда вы устанавливаете виджет ячейки, таблица становится его владельцем. Хотя вы можете переродить виджет, результат может быть неопределенным, поэтому лучше создать новый экземпляр на основе растрового изображения.

Совет: избегайте использования встроенных циклов if/else или for: в этом нет абсолютно никакой пользы, и единственный результат - это делает ваш код менее читаемым

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...