Erweiterte Buttenbar

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Nobuddy
User
Beiträge: 1019
Registriert: Montag 30. Januar 2012, 16:38

Hallo zusammen,
ich möchte eine Buttonbar unten erstellen, die unter anderem ein komplettes Suchfeld enthält, mit der Option nach unten zu erweitern, z.B. mit "find, replace, replace all".
Ich versuche mit QGridLayout zwei horizonzale Bereiche zu erstellen, leider ist alles in einem Bereich.
Mein Code ist lauffähig.
Hoffe, Ihr könnt mir dabei helfen :wink:

Code: Alles auswählen

import sys
from PyQt5.QtCore import (
	Qt,
	)
from PyQt5.QtWidgets import (
	QApplication,
	QMainWindow,
	QMdiArea,
	QComboBox,
	QGridLayout,
	QLineEdit,
	QPushButton,
	QToolBar,
	QWidget,
	)
from PyQt5.QtGui import  (
	QFont,
	)

class ButtonBar(QToolBar):

	def __init__(self, parent=None):
		super().__init__(parent=parent)

		self.parent = parent
		self.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
		self.verticalLayout = QVBoxLayout()
		self.layout = QGridLayout()
		fontSize = 14
		self.font = QFont('NimbusSansL', fontSize)
		parent.searchComboSelection = 'AUTO', 'COMBO', 'SEARCH', 'REPLACE'
		firstBarBelow = ['search', 'back', 'next']
		secodBarBelow = ['find', 'replace', 'replace all']
		for y, bar in enumerate([firstBarBelow, secodBarBelow]):
			for x, button in enumerate(bar):
				if button == 'search':
					# create cömbobox
					self.setComboBox(fontSize)
					# create searchfield in toolbar
					self.setSearchArea(fontSize)
				self.layout.addWidget(self.setPushButton(button), y, x)
		self.setLayout(self.layout)

	def setComboBox(self, fontSize):
		cb = QComboBox(self)
		cb.setEnabled(True)
		cb.setObjectName('combobox')
		[cb.addItem(text) for text in self.parent.searchComboSelection]
		cb.setCurrentText('AUTO')
		self.comboState = cb.currentText()
		cb.activated[str].connect(self.onChanged)
		cb.setFont(self.font)
		self.addWidget(cb)

	def setSearchArea(self, fontSize):
		sF = QLineEdit()
		f = sF.font()      # lineedit current font
		f.setPointSize(fontSize)    # change it's size
		sF.setFont(f)      # set font
		sF.setFocusPolicy(Qt.StrongFocus)
		sF.setPlaceholderText('Eingabe Suche')
		sF.setObjectName('searchField')
		sF.resize(200,40)
		sF.setMaximumWidth(400)
		sF.setMinimumHeight(40)
		sF.setReadOnly(False) # True / False (write)
		sF.installEventFilter(self)
		self.addWidget(sF)

	def setPushButton(self, button):
		pushbutton = QPushButton(button.capitalize())
		pushbutton.setLayout(self.layout)
		pushbutton.setCheckable(False)	# True / False
		pushbutton.setEnabled(True)
		pushbutton.setFont(self.font)
		self.addWidget(pushbutton)

	def onChanged(self, text):
		print('onChanged', text)


class WindowMDI(QMainWindow):

	def __init__(self):
		super().__init__()

		self.mdi = QMdiArea()
		# set geomerty
		self.setGeometry(100, 300, 1000, 500)
		# toolbar below
		self.addToolBar(Qt.BottomToolBarArea, ButtonBar(parent=self))
		self.setCentralWidget(self.mdi)


def main():
	App = QApplication(sys.argv)
	obj = WindowMDI()
	title = 'PyQt5 QMainWindow'
	obj.setWindowTitle(title)
	obj.show()
	sys.exit(App.exec())

if __name__ == '__main__':
	main()
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Die gute Nachricht: ich habe nur eine Zeile entfernen muessen, und es lief tatsaechlich. Die schlechte Nachricht: mir ist unklar, was genau du erreichen willst, und was nicht funktioniert. Fuer mich sieht es gut aus(tm), aber das mag Ignoranz meinerseits sein.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Nachtrag: ich sehe gerade eine ganze Reihe von Fehlermeldungen/Warnungen, die sich danach anhoeren, dass die relevant sind:

Code: Alles auswählen

QLayout: Cannot add a null widget to QGridLayout/
QLayout: Cannot add a null widget to QGridLayout/
QLayout: Cannot add a null widget to QGridLayout/
QLayout: Cannot add a null widget to QGridLayout/
QLayout: Cannot add a null widget to QGridLayout/
QLayout: Cannot add a null widget to QGridLayout/
QWidget::setLayout: Attempting to set QLayout "" on ButtonBar "", which already has a layout
Nobuddy
User
Beiträge: 1019
Registriert: Montag 30. Januar 2012, 16:38

Hallo __deets__,
ja die Zeile habe ich auch entfernt und habe die gleiche Meldungen, wie Du.
Vielleicht habe ich da den falschen Ansatz gewählt.
Beim Erstellen der unteren ButtonBar, ist eine ComboBox mit Suchfeld integriert. Eigentlich möchte ich erreichen, dass bei der Auswahl "REPLACE" der ComboBox, sich dann unterhalb der ButtonBar eine zweite Zeile mit den Buttons "find, replace, replace all" erscheint, die dann wieder verschwindet, wenn diese nicht benötigt wird.
Ich habe erst mal versucht, beide Button Zeilen zu erstellen, was so nicht funktioniert.
Vielleicht kannst Du mir da die richtige Richtung zeigen?
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ok, auf die Gefahr hin wieder der boese Bube zu sein: warum? Es gibt wenig, was mehr nervt als nervoes rumzuckende UIs. Es gibt sowas, zB bei FreeCAD und seine Workbenches. Das ist aber ein etwas anderer Ansatz, da waehlt man quasi eine andere Art, mit dem Projekt umzugehen. Also eher sowas wie eine Konfiguration, die man untere mehreren auswaehlt.

Sowas wie du hier hast wuerde ich immer nur mit enable/disable machen, oder mit dedizierten Toolbars, die der User an/ausschalten kann. So ein geflacker, bei der dann die ComboBox unter deiner Maus verschwindet, weil du einen anderen Eintrag ausgewaehlt hast, ist der Horror. Dieser Fall tritt ein, wenn jemand (was Toolbars koennen, und User sich dann eben so einstellen) die Toolbar nach unten zieht. Und du ballerst dann eine zweite Zeile da rein, und die ComboBox springt davon...
Nobuddy
User
Beiträge: 1019
Registriert: Montag 30. Januar 2012, 16:38

Ok, das ist ein gutes Argument, mein Vorhaben anderst umzusetzen.
Die ButtonBar bei ComboBox Auswahl "REPLACE" zu ersetzen.
Diese würde dann die ComboBox, das Suchfeld und die Buttons "find, replace, replace all" enthalten. Wenn die ComboBox Auswahl NICHT "REPLACE" ist, dann die "Haupt-ButtonBar".
Das wäre so wohl besser.
Nobuddy
User
Beiträge: 1019
Registriert: Montag 30. Januar 2012, 16:38

Habe meinen Code umgeschrieben, so funktioniert es.

Code: Alles auswählen

import sys
from PyQt5.QtCore import (
	Qt,
	)
from PyQt5.QtWidgets import (
	QApplication,
	QMainWindow,
	QMdiArea,
	QComboBox,
	QGridLayout,
	QLineEdit,
	QPushButton,
	QToolBar,
	QWidget,
	)
from PyQt5.QtGui import  (
	QFont,
	)

class ButtonBar(QToolBar):

	def __init__(self, buttons, parent=None):
		super().__init__(parent=parent)
		self.parent = parent
		self.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
		fontSize = 14
		self.gridLayout = QGridLayout()
		self.font = QFont('NimbusSansL', fontSize)
		y = 0
		for x, name in enumerate(buttons):
			if name == 'search':
				# create cömbobox
				selection = 'AUTO', 'COMBO', 'SEARCH', 'REPLACE'
				parent.searchComboSelection = selection
				ComboBox(name, selection, parent.onChanged, self.font,
					parent=self)
				# create searchfield in toolbar
				TextField(name, fontSize, parent=self)
			pb = PushButton(name, self.gridLayout, parent=self)
			self.gridLayout.addWidget(pb, y, x)


class ComboBox(QComboBox):

	def __init__(self, name, selection, func, font, parent=None):
		super().__init__(parent=parent)

		self.setEnabled(True)
		try:
			self.setObjectName('{}Combo'.format(name.lower()))
		except AttributeError:
			self.setObjectName('combobox')
		[self.addItem(name) for name in selection]
		self.setCurrentText('AUTO')
		self.comboState = self.currentText()
		self.activated[str].connect(func)
		self.setFont(font)
		parent.addWidget(self)


class TextField(QLineEdit):

	def __init__(self, name, fontSize, parent=None):
		super().__init__(parent=parent)

		f = self.font()      # lineedit current font
		f.setPointSize(fontSize)    # change it's size
		self.setFont(f)      # set font
		self.setFocusPolicy(Qt.StrongFocus)
		self.setPlaceholderText('Eingabe')
		self.setObjectName('{}Field'.format(name.lower()))
		self.resize(200,40)
		self.setMaximumWidth(400)
		self.setMinimumHeight(40)
		self.setReadOnly(False) # True / False (write)
		self.installEventFilter(parent)
		parent.addWidget(self)


class PushButton(QWidget):

	def __init__(self, button, layout, parent=None):
		super().__init__(parent=parent)

		pb = QPushButton(button.capitalize())
		pb.setLayout(layout)
		pb.setCheckable(False)	# True / False
		pb.setEnabled(True)
		pb.setFont(parent.font)
		parent.addWidget(pb)


class WindowMDI(QMainWindow):

	def __init__(self):
		super().__init__()

		self.mdi = QMdiArea()
		# set geomerty
		self.setGeometry(100, 300, 1000, 500)
		# toolbar below
		self.firstBarBelow = ['search', 'back', 'next']
		self.secondBarBelow = ['search', 'find', 'replace', 'replace all']
		self.firstBB = ButtonBar(self.firstBarBelow, parent=self)
		self.addToolBar(Qt.BottomToolBarArea, self.firstBB)
		self.setCentralWidget(self.mdi)

	def onChanged(self, name):
		print('onChanged', name)
		if name == 'REPLACE':
			self.firstBB.setParent(None)
			self.secondBB = ButtonBar(
				self.secondBarBelow, parent=self
				)
			self.addToolBar(
				Qt.BottomToolBarArea, self.secondBB
				)
		else:
			self.secondBB.setParent(None)
			self.firstBB = ButtonBar(
				self.firstBarBelow, parent=self
				)
			self.addToolBar(
				Qt.BottomToolBarArea, self.firstBB
				)

def main():
	App = QApplication(sys.argv)
	obj = WindowMDI()
	title = 'PyQt5 QMainWindow'
	obj.setWindowTitle(title)
	obj.show()
	sys.exit(App.exec())

if __name__ == '__main__':
	main()
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Nicht fuer mich:

Code: Alles auswählen

$ python3 /tmp/test.py 
onChanged COMBO
Traceback (most recent call last):
  File "/tmp/test.py", line 119, in onChanged
    self.secondBB.setParent(None)
AttributeError: 'WindowMDI' object has no attribute 'secondBB'
onChanged SEARCH
Traceback (most recent call last):
  File "/tmp/test.py", line 119, in onChanged
    self.secondBB.setParent(None)
AttributeError: 'WindowMDI' object has no attribute 'secondBB'
onChanged REPLACE
Nobuddy
User
Beiträge: 1019
Registriert: Montag 30. Januar 2012, 16:38

Hatte auch die Fehlermeldung. Bei nochmaligem Testen kam diese aber nicht mehr ... komisch.
Ich habe folgendes abgeändert.

Code: Alles auswählen

	def onChanged(self, name):
		print('onChanged', name)
		if name == 'REPLACE':
			self.replaceBar = True
			self.firstBB.setParent(None)
			self.firstBB.deleteLater()	# <<<<<<<<<<<<<
			self.secondBB = ButtonBar(
				self.secondBarBelow, parent=self
				)
			self.addToolBar(
				Qt.BottomToolBarArea, self.secondBB
				)
		else:
			self.replaceBar = False
			self.secondBB.setParent(None)
			self.secondBB.deleteLater()	# <<<<<<<<<<<<<
			self.firstBB = ButtonBar(
				self.firstBarBelow, parent=self
				)
			self.addToolBar(
				Qt.BottomToolBarArea, self.firstBB
				)
ButtonBar wird entfernt und bei Bedarf neu erstellt.
Benutzeravatar
Axel-WAK
User
Beiträge: 62
Registriert: Dienstag 29. November 2022, 11:52

Das funktioniert so auch nicht, beim Wählen von Combo hast Du die Widgets doppelt. Du solltest das Konzept neu überdenken.
OS: LMDE5 *** Homepage *** Github Seite
Nobuddy
User
Beiträge: 1019
Registriert: Montag 30. Januar 2012, 16:38

Bin dabei, gebe nicht so schnell auf :wink:
Benutzeravatar
Axel-WAK
User
Beiträge: 62
Registriert: Dienstag 29. November 2022, 11:52

Wäre es nicht sogar sinnvoller alle Buttons zu haben ohen erst eine ComboBox zu bemühen?

Code: Alles auswählen

import sys
from PyQt5.QtCore import (
	Qt,
	)
from PyQt5.QtWidgets import (
	QApplication,
	QMainWindow,
	QMdiArea,
	QGridLayout,
	QLineEdit,
	QPushButton,
	QToolBar,
	QWidget,
	)

class ButtonBar(QToolBar):

	def __init__(self, buttons, parent=None):
		super().__init__(parent=parent)
		self.setStyleSheet("""QToolBar{spacing: 3px; margin-top: 5px; border: 0px;} 
								QPushButton{font-family:NimbusSansL; font-size: 14pt;} 
								QLineEdit{font-family:NimbusSansL; font-size: 14pt;}""")

		self.parent = parent
		self.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
		self.gridLayout = QGridLayout()
		y = 0
		for x, name in enumerate(buttons):
			if name == 'search':
				# create searchfield in toolbar
				TextField(name, parent=self)
			else:
				pb = PushButton(name, self.gridLayout, parent=self)
				self.gridLayout.addWidget(pb, y, x)


class TextField(QLineEdit):

	def __init__(self, name, parent=None):
		super().__init__(parent=parent)
		self.setFocusPolicy(Qt.StrongFocus)
		self.setPlaceholderText('Eingabe')
		self.setObjectName('{}Field'.format(name.lower()))
		self.resize(200, 30)
		self.setMaximumWidth(400)
		self.setMinimumHeight(32)
		self.setReadOnly(False) # True / False (write)
		self.installEventFilter(parent)
		parent.addWidget(self)


class PushButton(QWidget):

	def __init__(self, button, layout, parent=None):
		super().__init__(parent=parent)

		pb = QPushButton(button.capitalize())
		pb.setLayout(layout)
		pb.setCheckable(False)	# True / False
		pb.setEnabled(True)
		parent.addWidget(pb)


class WindowMDI(QMainWindow):

	def __init__(self):
		super().__init__()

		self.mdi = QMdiArea()
		# set geomerty
		self.setGeometry(100, 300, 1000, 500)
		self.setContentsMargins(10, 10, 10 ,10)
		# toolbar below
		self.secondBarBelow = ['search', 'find', 'replace', 'replace all', 'back', 'next']
		self.firstBB = ButtonBar(self.secondBarBelow, parent=self)
		self.addToolBar(Qt.BottomToolBarArea, self.firstBB)
		self.setCentralWidget(self.mdi)

def main():
	App = QApplication(sys.argv)
	obj = WindowMDI()
	title = 'PyQt5 QMainWindow'
	obj.setWindowTitle(title)
	obj.show()
	sys.exit(App.exec())

if __name__ == '__main__':
	main()
OS: LMDE5 *** Homepage *** Github Seite
Nobuddy
User
Beiträge: 1019
Registriert: Montag 30. Januar 2012, 16:38

Nein, ich möchte das nach Anwendungsfall steuern.
Je nach Anwendungsfall, werden nicht alle Buttons benötigt, bzw. andere Buttons benötigt.

Mittlerer Weile, bin ich auf dem richtigen Weg.

Code: Alles auswählen

import sys
from PyQt5.QtCore import (
	Qt,
	)
from PyQt5.QtWidgets import (
	QApplication,
	QMainWindow,
	QMdiArea,
	QComboBox,
	QGridLayout,
	QLineEdit,
	QTextEdit,
	QPushButton,
	QToolBar,
	QWidget,
	)
from PyQt5.QtGui import  (
	QFont,
	)

# Areas of buttonbar below
AREAS = {
	'start' : ['search'],
	'table' : ['search', 'back', 'next', 'new', 'delete'],
	'replace' : ['search', 'find', 'replace', 'find all', 'replace all'],
	}

class ButtonBar(QToolBar):

	def __init__(self, area, parent=None):
		super().__init__(parent=parent)

		self.parent = parent
		try:
			className = parent.object.__class__.__name__
		except AttributeError:
			# not parent.object
			try:
				# if test
				parent.test
				className = True
			except AttributeError:
				className = False
		self.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
		fontSize = 14
		gridLayout = QGridLayout()
		func = parent.mainBarCallback
		self.font = QFont('NimbusSansL', fontSize)
		y = 0
		for x, name in enumerate(AREAS[area]):
			self.addSeparator()
			if name == 'search':
				# create cömbobox
				selection = 'AUTO', 'COMBO', 'SEARCH', 'REPLACE'
				parent.searchComboSelection = selection
				self.cb = ComboBox(name, selection, self.comboChanged,
					self.font, parent=self)
				# create searchfield in toolbar
				textField = TextField(name, fontSize, parent=self)
				self.addSeparator()
			if name == 'search' and 'find' in AREAS[area]:
				self.cb.setCurrentText('REPLACE')
				continue
			pb = PushButton(name, gridLayout, func, parent=self)
			if not className:
				self.cb.setEnabled(False)
				textField.setReadOnly(True)
				pb.setEnabled(False)
			self.addSeparator()
			gridLayout.addWidget(QWidget(pb), y, x)

	def comboChanged(self, text):
		print('comboChanged: ', text)
		self.comboState = text
		self.buttonWidget['searchCombo'].setCurrentText(text)
		self.buttonWidget['searchField'].setText('')
		self.buttonWidget['searchField'].setFocus()
		self.buttonBarCallback(text)

	def buttonBarCallback(self, name):
		print('buttonBarCallback: ', name)
		self.parent.buttonArea.setParent(None)
		self.parent.buttonArea.deleteLater()
		self.parent.buttonArea.close()
		self.searchBar = False
		self.replaceBar = False
		if name == 'REPLACE':
			self.replaceBar = True
			area = name.lower()
		else:
			self.searchBar = True
			area = 'start'
		self.parent.buttonArea = ButtonBar(area, parent=self.parent)
		self.parent.addToolBar(
			Qt.BottomToolBarArea, self.parent.buttonArea)
		self.cb.setCurrentText(name)


class ComboBox(QComboBox):

	def __init__(self, name, selection, func, font, parent=None):
		super().__init__(parent=parent)

		self.setEnabled(True)
		try:
			self.setObjectName('{}Combo'.format(name.lower()))
		except AttributeError:
			self.setObjectName('combobox')
		[self.addItem(name) for name in selection]
		self.setCurrentText('AUTO')
		self.comboState = self.currentText()
		self.activated[str].connect(func)
		self.setFont(font)
		parent.buttonWidget = {'searchCombo' : self}
		parent.addWidget(self)


class TextField(QLineEdit):

	def __init__(self, name, fontSize, parent=None):
		super().__init__(parent=parent)

		self.parent = parent
		f = self.font()      # lineedit current font
		f.setPointSize(fontSize)    # change it's size
		self.setFont(f)      # set font
		self.setFocusPolicy(Qt.StrongFocus)
		self.setPlaceholderText('Eingabefeld')
		self.setObjectName('{}Field'.format(name.lower()))
		self.resize(200,40)
		self.setMaximumWidth(400)
		self.setMinimumHeight(40)
		self.setReadOnly(False) # True / False (write)
		self.installEventFilter(parent)
		self.textChanged[str].connect(self.searchFieldCallback)
		parent.buttonWidget['searchField'] = parent.searchField = self
		parent.addWidget(self)

	def searchFieldCallback(self, name):
		print('searchFieldCallback: ', name)
		# state to combobox
		state = self.parent.buttonWidget['searchCombo'].currentText()
		if state == 'COMBO':
			# get text to search field
			name = name.upper()
			self.parent.buttonWidget['searchField'].setText(name)
		self.parent.buttonSearch()
		self.parent.buttonWidget['searchField'].setFocus()


class PushButton(QPushButton):

	def __init__(self, name, layout, func, parent=None):
		super().__init__(parent=parent)

		self.setText(name.capitalize())
		self.clicked.connect(func)
		self.setLayout(layout)
		self.setCheckable(False)	# True / False
		self.setEnabled(True)
		self.setFont(parent.font)
		try:
			parent.buttonWidget[name] = self
		except AttributeError:
			parent.buttonWidget = {name : self}
		parent.addWidget(self)

class WindowMDI(QMainWindow):

	def __init__(self):
		super().__init__()

		self.mdi = QMdiArea()
		# set geomerty
		self.setGeometry(100, 300, 1000, 500)
		# toolbar below
		self.test = True
		self.buttonArea = ButtonBar('start', parent=self)
		self.addToolBar(Qt.BottomToolBarArea, self.buttonArea)
		self.buttonBarMemory = dict()
		self.toolBarMemory = dict()
		# attribute for messagebox
		self.resultMB = QTextEdit()
		self.resultMB.setPlainText('False')
		self.setCentralWidget(self.mdi)

	#@pyqtSlot()
	def mainBarCallback(self):
		self.buttonJob = self.sender().text().lower()
		print('mainBarCallback: ', self.buttonJob)
		jobArea = {
			'search' : self.jobFunc,
			'back' : self.jobFunc,
			'next' : self.jobFunc,
			'new' : self.jobFunc,
			'delete' : self.jobFunc,
			'find' : self.jobFunc,
			'replace' : self.jobFunc,
			'find all' : self.jobFunc,
			'replace all' : self.jobFunc,
			}[self.buttonJob]()

	def jobFunc(self):
		print('Do the work for buttonJob: < {} >'.format(self.buttonJob))

def main():
	App = QApplication(sys.argv)
	obj = WindowMDI()
	title = 'PyQt5 QMainWindow'
	obj.setWindowTitle(title)
	obj.show()
	sys.exit(App.exec())

if __name__ == '__main__':
	main()
Benutzeravatar
Axel-WAK
User
Beiträge: 62
Registriert: Dienstag 29. November 2022, 11:52

Stürzt schon ab beim Eingabefeld

Code: Alles auswählen

AttributeError: 'ButtonBar' object has no attribute 'buttonSearch'
OS: LMDE5 *** Homepage *** Github Seite
Nobuddy
User
Beiträge: 1019
Registriert: Montag 30. Januar 2012, 16:38

Ja, habe ich behoben, hier nochmals das Neuste.

Code: Alles auswählen

import sys
from PyQt5.QtCore import (
	Qt,
	)
from PyQt5.QtWidgets import (
	QApplication,
	QMainWindow,
	QMdiArea,
	QComboBox,
	QGridLayout,
	QLineEdit,
	QTextEdit,
	QPushButton,
	QToolBar,
	QWidget,
	)
from PyQt5.QtGui import  (
	QFont,
	)

# Areas of buttonbar below
AREAS = {
	'start' : ['search'],
	'table' : ['search', 'back', 'next', 'new', 'delete'],
	'replace' : ['search', 'search', 'find', 'replace', 'find all',
		'replace all', 'text change back'],
	}

class ButtonBar(QToolBar):

	def __init__(self, area, parent=None):
		super().__init__(parent=parent)

		self.parent = parent
		try:
			className = parent.object.__class__.__name__
		except AttributeError:
			# not parent.object
			try:
				# if test
				parent.test
				className = True
			except AttributeError:
				className = False
		self.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
		fontSize = 14
		parent.gridLayoutBarArea = QGridLayout()
		func = parent.mainBarCallback
		self.font = QFont('NimbusSansL', fontSize)
		try:
			self.buttonWidget
		except AttributeError:
			self.buttonWidget = dict()
		y = 0
		try:
			names = AREAS[area]
		except KeyError:
			return
		for x, name in enumerate(names):
			self.addSeparator()
			if name == 'search':
				try:
					s += 1
				except UnboundLocalError:
					s = 0
				if s == 0:
					# create cömbobox
					selection = 'AUTO', 'COMBO', 'SEARCH', 'REPLACE'
					parent.searchComboSelection = selection
					self.cb = ComboBox(name, selection, self.comboChanged,
						self.font, parent=self)
					parent.gridLayoutBarArea.addWidget(QWidget(self.cb), y, x)
				# create searchfield in toolbar
				placeHolderText = 'Eingabefeld'
				if s == 1:
					placeHolderText = 'Suchfeld'
				tF = TextField(name, placeHolderText, fontSize, parent=self)
				parent.gridLayoutBarArea.addWidget(QWidget(tF), 0, x)
				parent.buttonSearch()
				self.addSeparator()
			if name == 'search' and 'find' in AREAS[area]:
				self.cb.setCurrentText('REPLACE')
				continue
			pb = PushButton(name, parent.gridLayoutBarArea, func, parent=self)
			parent.gridLayoutBarArea.addWidget(QWidget(pb), y, x)
			if not className:
				self.cb.setEnabled(False)
				tF.setReadOnly(True)
				pb.setEnabled(False)
			if (name == 'back' or name == 'next'  or name == 'replace'
					or name == 'replace all' or name == 'text change back'):
				pb.setEnabled(False)
			self.addSeparator()
		self.setObjectName(area)
		parent.buttonWidget = self.buttonWidget

	def comboChanged(self, text):
		print('comboChanged: ', text)
		self.comboState = text
		self.buttonWidget['searchCombo'].setCurrentText(text)
		self.buttonWidget['searchField'].setText('')
		self.buttonWidget['searchField'].setFocus()
		self.parent.buttonBarCallback(text)
		if text == 'COMBO' or text == 'AUTO':
			self.parent.buttonCombo()
		elif text == 'REPLACE':
			print('+++++++++++++++++++++++++++++++++')

	def searchFieldCallback(self, text):
		print('searchFieldCallback', text)
		# state to combobox
		state = self.buttonWidget['searchCombo'].currentText()
		# get text to search field
		if state == 'COMBO':
			text = text.upper()
		self.focusWidget().setText(text)
		self.focusWidget().setFocus()
		self.parent.buttonSearch()


class ComboBox(QComboBox):

	def __init__(self, name, selection, func, font, parent=None):
		super().__init__(parent=parent)

		self.setEnabled(True)
		objectName = '{}Combo'.format(name.lower())
		self.setObjectName(objectName)
		comboState = 'AUTO'
		self.setCurrentText(comboState)
		[self.addItem(name) for name in selection]
		self.comboState = self.currentText()
		self.activated[str].connect(func)
		self.setFont(font)
		parent.buttonWidget = {'searchCombo' : self}
		parent.buttonWidget[objectName] = self
		parent.addWidget(self)


class TextField(QLineEdit):

	def __init__(self, name, placeHolderText, fontSize, parent=None):
		super().__init__(parent=parent)

		self.parent = parent
		objectName = '{}Field'.format(name.lower())
		if placeHolderText == 'Suchfeld':
			objectName = 'replaceField'
			placeHolderText = 'Ersatztext'
		self.setObjectName(objectName)
		self.setPlaceholderText(placeHolderText)
		f = self.font()      # lineedit current font
		f.setPointSize(fontSize)    # change it's size
		self.setFont(f)      # set font
		self.setFocusPolicy(Qt.StrongFocus)
		self.resize(200,40)
		self.setMaximumWidth(400)
		self.setMinimumHeight(40)
		self.setReadOnly(False) # True / False (write)
		self.installEventFilter(parent)
		self.textChanged[str].connect(parent.searchFieldCallback)
		parent.buttonWidget[objectName] = self
		parent.addWidget(self)


class PushButton(QPushButton):

	def __init__(self, name, layout, func, parent=None):
		super().__init__(parent=parent)

		objectName = name.lower()
		self.setObjectName(objectName)
		self.setText(name.capitalize())
		self.clicked.connect(func)
		self.setLayout(layout)
		self.setCheckable(False)	# True / False
		self.setEnabled(True)
		self.setFont(parent.font)
		try:
			parent.buttonWidget[name] = self
		except AttributeError:
			parent.buttonWidget = {name : self}
		parent.buttonWidget[name] = self
		parent.addWidget(self)

class WindowMDI(QMainWindow):

	def __init__(self):
		super().__init__()

		self.mdi = QMdiArea()
		# set geomerty
		self.setGeometry(100, 300, 1000, 500)
		# toolbar below
		self.test = True
		self.buttonArea = ButtonBar('start', parent=self)
		self.addToolBar(Qt.BottomToolBarArea, self.buttonArea)
		self.buttonBarMemory = dict()
		self.toolBarMemory = dict()
		# attribute for messagebox
		self.resultMB = QTextEdit()
		self.resultMB.setPlainText('False')
		self.setCentralWidget(self.mdi)

	def buttonCombo(self):
		print('buttonSearch')

	def buttonBarCallback(self, name):
		print('buttonBarCallback: ', name)
		if name == 'COMBO':
			return
		print('objectName: ', self.buttonArea.objectName())
		self.buttonArea.setParent(None)
		self.buttonArea.deleteLater()
		self.buttonArea.close()
		self.searchBar = False
		self.replaceBar = False
		if name == 'REPLACE':
			self.replaceBar = True
			area = name.lower()
		else:
			self.searchBar = True
			area = 'start'
		self.buttonArea = ButtonBar(area, parent=self)
		self.addToolBar(Qt.BottomToolBarArea, self.buttonArea)

	#@pyqtSlot()
	def mainBarCallback(self):
		self.buttonJob = self.sender().text().lower()
		print('Do the work for buttonJob: < {} >'.format(self.buttonJob))

	def buttonSearch(self):
		print('buttonSearch')

def main():
	App = QApplication(sys.argv)
	obj = WindowMDI()
	title = 'PyQt5 QMainWindow'
	obj.setWindowTitle(title)
	obj.show()
	sys.exit(App.exec())

if __name__ == '__main__':
	main()
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ui. Das sieht sehr problematisch aus. Diese ganze attribut-getterei, und className ist True/False, statt ein Name zu sein (oder vielleicht None), und ganz generell ist es ein riesen Entwurfsproblem, wenn ein Kind-Widget sich so viel Wissen ueber die Widgets ueber im durch die parent-relation aufsammelt. Auch einen UnboundLocalError faengt man *niemals* ab - das ist drumrumarbeiten um einen Programmierfehler!
Nobuddy
User
Beiträge: 1019
Registriert: Montag 30. Januar 2012, 16:38

Ja, da habe ich wohl noch einiges zu lernen.
Die Classen "ComboBox, TextField, PushButton" habe ich aus ButtonBar herausgenommen, da ich diese auch für andere Aufgaben verwenden möchte.
Bei mir, ist der Weg das Ziel :wink:

Vielleicht kannst Du mir Beispiele zeigen, wie es besser geht?
Benutzeravatar
Axel-WAK
User
Beiträge: 62
Registriert: Dienstag 29. November 2022, 11:52

Nobuddy hat geschrieben: Freitag 20. Januar 2023, 16:42 Bei mir, ist der Weg das Ziel :wink:
Aber was ist das Ziel? Was soll es am Ende werden? Ein Texteditor mit Suchen/Ersetzen ?
OS: LMDE5 *** Homepage *** Github Seite
Nobuddy
User
Beiträge: 1019
Registriert: Montag 30. Januar 2012, 16:38

Nein, bin Rentner und interesiere mich für Python und Qt.
Das, was hier mein Ziel war, die untere Buttonbar, nach verschiedenen Anforderungen zu gestalten.
Ich habe ein Hauptfenster MDI, aus dem ich auf Dateien zugreifen und öffnen kann. Textdateien und Tabellen, werden im MDI angezeigt.
Bei Textdateien gibt es viele Möglichkeiten, diese zu bearbeiten. Hatte mir überlegt, Text zu durchsuchen und Teile ersetzen zu können, daher auch bei der ComboBox Auswahl "REPLACE", die eine neue Buttonbar anbietet.
Ich habe das in meinem MDI integriert und bin weiter am Optimieren. :wink:
Antworten