Die Tab-Geschichte, brauche ich vorerst nicht, später ja.
Aber da kann ich mich ja nochmals melden.
Bin gerade dabei meinen bisherigen Qt4-Code in Qt5-Code umzuwandeln.
Puh, da hat sich wirklich was getan und verändert...
Grüße und Danke für Deine Hilfe!
Nobuddy
FocusIn, Item-Position in Dataset-Tabelle ermitteln
Komme nochmals auf das Thema zurück.
Der bisherige Code, mit focusEvent funktioniert, geändertes Item wird ohne Fkus setzen auf ein anderes Item übernommen.
Da bei dem bisherigen Test-Code, kein Close-Button integriert war, konnten wir auch dies nicht testen.
Die geänderten Daten des Items ohne FocusOut, werden nicht übernommen.
Deshalb habe ich mich bemüht, dies zu ändern.
Dank Deiner bisherigen nicht benötigten Funktion "_item_clicked", habe ich eine Lösung gefunden.
Ich poste mal den Teil-Code dazu, siehe bei Funktion "close" die erste Zeile.
Der bisherige Code, mit focusEvent funktioniert, geändertes Item wird ohne Fkus setzen auf ein anderes Item übernommen.
Da bei dem bisherigen Test-Code, kein Close-Button integriert war, konnten wir auch dies nicht testen.
Die geänderten Daten des Items ohne FocusOut, werden nicht übernommen.
Deshalb habe ich mich bemüht, dies zu ändern.
Dank Deiner bisherigen nicht benötigten Funktion "_item_clicked", habe ich eine Lösung gefunden.
Ich poste mal den Teil-Code dazu, siehe bei Funktion "close" die erste Zeile.
Code: Alles auswählen
def _item_clicked(self, index):
# numeric position of dataset
pos2dataset = index.row()
# in front of item
self.item_after = index.sibling(1,0)
# in front of item
item_before = index.sibling(-1,0)
def exec_(self):
self.view.setCurrentIndex(self.item_after)
self.dataset = [self.model.invisibleRootItem().child(i).text()
for i in range(len(self.header))]
if self.dataset != self.old_dataset:
r = MessageBox(QMessageBox.Yes, 'Änderung speichern?')
if r.result() != QMessageBox.Yes:
self.dataset = self.old_dataset
print('self.dataset', self.dataset)
Ich kann nur raten was du wirklich meinst: das man das Hauptfenster schliessen kann, ohne das es zu einer Uebernahme der Daten kommt? Das loest man mE anders. Du solltest das auf globaler Ebene verankern. Dein gesamtes Programm sollte nicht beendet werden koennen, wenn irgendwo Daten eingegeben wurden. Mir ist so, als ob es dazu einen Mechanismus gibt, muss den mal recherchieren.
- __blackjack__
- User
- Beiträge: 13103
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
Das ist ja auch genau das Verhalten was Benutzer von anderen Programmen her kennen, dass ein Programm nachfragt ob das Schliessen abgebrochen werden soll, oder die veränderten Daten vor dem Schliessen gespeichert oder verworfen werden sollen. Wenn man die Daten einfach ungefragt speichert, kann das Benutzer auch sehr verärgern, weil man damit nicht rechnet das so etwas einfach ungefragt passiert.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Ich habe alle Buttons zentral in der MDI angelegt, die steuen dann das activeSubWindow.
Die benötigten Buttons für das activeSubWindow werden entsprechend aktualisiert.
Die Buttons, sind in einem ToolBar verankert, ich sehe das als einfachste Lösung.
Zuerst hatte ich die Buttons in den jeweiligen activeSubWindow integriert, bin dann aber zu der Auffassung gekommen, dies zu zentralisieren. Einen Datensatz zu editieren, löschen oder einen Neuen hinzufügen, bleibt letztednlich immer das Gleiche.
Nun nochmals auf meinen letzten Post zurück zu kommen.
Beim Beenden des Dataset-Windows durch den Close-Button, werden Änderungen nicht übernommen, wenn man nicht das Item verlässt. Ganz anderst ist es ja, wenn ich das Dataset-Window durch den closeEvent beende. Das hat mich auch zu letzterer Lösung gebracht. Das sichert die gemachte Änderung, die dann durch eine MessageBox abgefragt wird (Bestätigung positiv/negativ).
Wenn es dafür noch eine einfachere Lösung gibt, kannst Du mir das gerne aufzeigen, ich lerne immer gerne dazu.
Die benötigten Buttons für das activeSubWindow werden entsprechend aktualisiert.
Die Buttons, sind in einem ToolBar verankert, ich sehe das als einfachste Lösung.
Zuerst hatte ich die Buttons in den jeweiligen activeSubWindow integriert, bin dann aber zu der Auffassung gekommen, dies zu zentralisieren. Einen Datensatz zu editieren, löschen oder einen Neuen hinzufügen, bleibt letztednlich immer das Gleiche.
Nun nochmals auf meinen letzten Post zurück zu kommen.
Beim Beenden des Dataset-Windows durch den Close-Button, werden Änderungen nicht übernommen, wenn man nicht das Item verlässt. Ganz anderst ist es ja, wenn ich das Dataset-Window durch den closeEvent beende. Das hat mich auch zu letzterer Lösung gebracht. Das sichert die gemachte Änderung, die dann durch eine MessageBox abgefragt wird (Bestätigung positiv/negativ).
Wenn es dafür noch eine einfachere Lösung gibt, kannst Du mir das gerne aufzeigen, ich lerne immer gerne dazu.
- __blackjack__
- User
- Beiträge: 13103
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
@Nobuddy: Ich würde das ja in die Fenster integrieren und ja, richtige Fenster. Für MDI muss man IMHO in Zeiten wo mehr als ein Monitor nichts exotisches mehr ist, schon eine gute Begründung haben. MDI empfinde ich immer als nervig und einschränkend. Und dass das letztlich immer das Gleiche bleibt: Warum ist das ein Argument es nicht in die Fenster zu integrieren? Auch dann muss man den immer gleichen Code ja nur *einmal* schreiben. Man hat ja nicht den Code für jedes Fenster einzeln und kopiert‽
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
An mehrere Monitore, habe ich jetzt nicht gedacht, da wäre dann auf jeden Fall das Integrieren der Buttons in die einzelnen Fenster wichtig. Diese Szenario brauche ich jetzt für mich nicht. Eine anschließende Änderung für mehrere Monitore, wäre dann schon eine Herausforderung.
Ich habe mich MDI angefreundet, obwohl es da nicht gerade übermäßig viele Resultate beim Googeln gibt.
Mir fehlt einfach das Gesamtwissen über Py und PyQt, um andere Lösungen schnell und einfach umsetzen zu können, was Ihr mit "links" macht. Für mich ist es wichtig, meinen Code zu verstehen.
Ich lerne gerne dazu. Was ich auch verstanden habe und Ihr mir versucht habt nahezulegen, den Code so einfach wie möglich zu halten, bzw. den Code in einzelne Funktionen aufzuteilen. Da bin ich heute schon ein kleinen Schritt dem näher gekommen.
Ich habe mich MDI angefreundet, obwohl es da nicht gerade übermäßig viele Resultate beim Googeln gibt.
Mir fehlt einfach das Gesamtwissen über Py und PyQt, um andere Lösungen schnell und einfach umsetzen zu können, was Ihr mit "links" macht. Für mich ist es wichtig, meinen Code zu verstehen.
Ich lerne gerne dazu. Was ich auch verstanden habe und Ihr mir versucht habt nahezulegen, den Code so einfach wie möglich zu halten, bzw. den Code in einzelne Funktionen aufzuteilen. Da bin ich heute schon ein kleinen Schritt dem näher gekommen.
Ich habe hier mal den Test-Code für das Dataset-Window, der lauffähig ist für Euch zum Testen, damit Ihr die Funktionsweise nachvollziehen könnt.
Code: Alles auswählen
import os
import sys
import operator # used for sorting
from PyQt5 import QtCore
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import (Qt, QSize, QEvent, QObject,
QSortFilterProxyModel)
from PyQt5.QtGui import QStandardItem, QStandardItemModel
from PyQt5.QtWidgets import (QMainWindow, QMdiArea, QWidget, QMessageBox,
QToolBar, QTableView, QGridLayout, QHBoxLayout, QAction, QApplication,
qApp)
title = 'Backlight management'
header = ['Pos', 'Supplier', 'Artikel', 'Benennung']
mylist = [['001', 'Meyer', '47110', 'Bratwurst weiss, 125 g'],
['002', 'Meyer', '47111', 'Bratwurst weiss, 425 g'],
['003', 'Meyer', '47112', 'Bratwurst weiss, 1225 g']]
columnWidths = [20, 15, 20, 40]
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.setWindowTitle("MDI demo")
self.mdi_area = QMdiArea()
self.setCentralWidget(self.mdi_area)
## Toolbar
screen_position = 'below'
buttons = [
['close', 'Ctrl+Q', self.close],
]
ToolBar(self, screen_position, buttons)
self.mylist = mylist
self.index = 0
sub = Dataset(self, mylist[self.index], header, columnWidths)
sub.setWindowTitle(title)
self.mdi_area.addSubWindow(sub)
sub.show()
def close(self):
print('CLOSE')
if self.mdi_area.activeSubWindow():
self.mdi_area.activeSubWindow().widget().exec_()
self.mdi_area.removeSubWindow(self.mdi_area.activeSubWindow())
return
qApp.quit()
class Dataset(QWidget):
def __init__(self, parent, dataset, header, columnWidths):
super(Dataset, self).__init__()
self.parent = parent
self.old_dataset = self.dataset = dataset
self.old_list = self.parent.mylist
self.header = header
try:
self.width = max(columnWidths)
except TypeError:
self.width = columnWidths
self.setObjectName('DATASET')
self.installEventFilter(self)
self.setFocusPolicy(Qt.StrongFocus)
self.view = QTableView(self)
self.view.clicked.connect(self._item_clicked)
# GridLayout
grid = QGridLayout()
grid.addWidget(self.view, 0, 0)
self.setLayout(grid)
self.model = QStandardItemModel()
# Load dataset
[self.model.invisibleRootItem().appendRow(
QStandardItem(column)) for column in self.dataset]
# Vertical header
[self.model.setHeaderData(i, Qt.Vertical, column)
for i, column in enumerate(header)]
self.proxy = QSortFilterProxyModel(self)
self.proxy.setSourceModel(self.model)
self.view.setModel(self.proxy)
def _item_clicked(self, index):
# numeric position of dataset
pos2dataset = index.row()
# in front of item
self.item_after = index.sibling(1,0)
# in front of item
item_before = index.sibling(-1,0)
def closeEvent(self, event):
self.exec_()
event.accept()
def exec_(self):
try:
self.view.setCurrentIndex(self.item_after)
except AttributeError:
pass
self.dataset = [self.model.invisibleRootItem().child(i).text()
for i in range(len(self.header))]
if self.dataset != self.old_dataset:
r = MessageBox(QMessageBox.Yes, 'Änderung speichern?')
if r.result() != QMessageBox.Yes:
self.dataset = self.old_dataset
print('self.dataset', self.dataset)
return self.parent.mylist
class ToolBar(QToolBar):
def __init__(self, parent, position, buttons):
QToolBar.__init__(self)
# Change Font
font = self.font()
font.setFamily("Arial")
font.setPointSize(18)
self.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon)
#self.setToolButtonStyle(QtCore.Qt.ToolButtonTextUnderIcon)
positions = {
'up' : QtCore.Qt.TopToolBarArea,
'left' : QtCore.Qt.LeftToolBarArea,
'right' : QtCore.Qt.RightToolBarArea,
'below' : QtCore.Qt.BottomToolBarArea,
}
for button, shortcut, comand in buttons:
path = ''
action = QAction(QIcon(path), button.capitalize(), self)
try:
action.triggered.connect(comand)
except TypeError:
pass
action.setShortcut(shortcut)
action.setFont(font)
if path == '':
action.setCheckable(True)
widget = QWidget()
widget.setLayout(QHBoxLayout())
self.addWidget(widget)
self.addAction(action)
if position == 'right':
self.addSeparator()
parent.addToolBar(positions[position.lower()], self)
self.setAllowedAreas(
QtCore.Qt.TopToolBarArea
| QtCore.Qt.BottomToolBarArea
| QtCore.Qt.LeftToolBarArea
| QtCore.Qt.RightToolBarArea
)
self.setStyleSheet(
"color: blue;"
"background-color: yellow;"
"selection-color: red;"
"selection-background-color: blue;"
)
class MessageBox(QMessageBox):
def __init__(self, buttonReply, text):
QMessageBox.__init__(self)
self.setText(text)
if buttonReply == self.Ok:
self.setIcon(self.Warning)
self.setWindowTitle('Info')
self.setStandardButtons(self.Ok)
self.setEscapeButton(self.Cancel)
default = self.Cancel
elif buttonReply == self.Yes:
self.setIcon(self.Warning)
self.setWindowTitle('Question')
self.setStandardButtons(self.Yes | self.No)
default = self.No
elif buttonReply == self.Cancel:
self.setIcon(self.Question)
self.setWindowTitle('Question')
self.setStandardButtons(self.Yes | self.No | self.Cancel)
self.setEscapeButton(self.Cancel)
default = self.Cancel
elif buttonReply == self.Save:
self.setIcon(self.Question)
self.setWindowTitle('Save and Exit')
self.setStandardButtons(self.Save | self.Discard | self.Cancel)
self.setInformativeText('Änderung speichern?')
self.setEscapeButton(self.Cancel)
default = self.Cancel
self.setDefaultButton(default)
self.exec_()
def main():
app = QApplication(sys.argv)
ex = MainWindow()
ex.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()