Seite 1 von 1
Zugriff auf Widget aus Gridlayout - Problem
Verfasst: Mittwoch 7. November 2018, 21:25
von Felix92
Huhu,
und zwar habe ich 2 Probleme:
1. wie kann ich die Abstände der Buttons im Grid verändern ?
// setSpacing und setHorizontal / Vertical .. habe ich schon probiert
2. wie kann ich auf einzelne Buttons aus dem Grid zugreifen ?
#todo wie auf buttons im Grid zugreifen
#todo wenn button aus grid gedrückt setze diesen / x-1 / x+1 /y-1 /y+1 auf black
#todo wenn button schon schwarz setze ihn auf weiß
Ich muss dazu sagen ich habe noch nie mit PyQt gearbeitet da ich Anwendungen bisher immer mit Java(FX) geschrieben habe.
Ich wäre für jede Hilfe dankbar falls es im bisherigen Code Fehler bzw. unsauberen Code gibt wäre ich für jeden Hinweis ebenfalls dankbar !
MfG Felix
Hier mein bisheriger Code:
Code: Alles auswählen
import sys
import subprocess
from PyQt5.QtWidgets import (QWidget, QGridLayout, QPushButton, QApplication, )
class basicWindow(QWidget, QGridLayout):
def __init__(self):
super().__init__()
self.setWindowTitle('Game')
button1 = QPushButton("3 x 3", self)
button1.move(95, 30)
button1.setStyleSheet("background-color: yellow")
button1.clicked.connect(self.button1clicked)
button2 = QPushButton("4 x 4", self)
button2.move(245, 30)
button2.setStyleSheet("background-color: yellow")
button2.clicked.connect(self.button2clicked)
button3 = QPushButton("Restart", self)
button3.move(650, 30)
button3.setStyleSheet("background-color: yellow")
button3.clicked.connect(self.button3clicked)
def button1clicked(self):
grid_layout = QGridLayout()
self.setLayout(grid_layout)
for x in range(3):
for y in range(3):
button = QPushButton()
button.setFixedSize(80, 80)
button.setStyleSheet("background-color: white")
grid_layout.addWidget(button, x, y)
button.clicked.connect(self.printcolor)
def button2clicked(self):
grid_layout = QGridLayout()
self.setLayout(grid_layout)
for x in range(4):
for y in range(4):
button = QPushButton()
button.setFixedSize(80, 80)
button.setStyleSheet("background-color: white")
grid_layout.addWidget(button, x, y)
def printcolor(self, button):
button.setStyleSheet("background-color: black")
#todo wie auf buttons im Grid zugreifen
#todo wenn button aus grid gedrückt setze diesen / x-1 / x+1 /y-1 /y+1 auf black
#todo wenn button schon schwarz setze ihn auf weiß
def button3clicked(self):
self.close()
subprocess.call("python" + " game.py", shell=True)
if __name__ == '__main__':
app = QApplication(sys.argv)
window = basicWindow()
window.setStyleSheet("background-color: green")
window.resize(800, 800)
window.show()
sys.exit(app.exec_())

Re: Zugriff auf Widget aus Gridlayout - Problem
Verfasst: Mittwoch 7. November 2018, 22:37
von __deets__
Na merk dir doch die Buttons einfach. In einer geeigneten Datenstruktur. Nach welchem Kriterium willst du denn auf die zugreifen?
Re: Zugriff auf Widget aus Gridlayout - Problem
Verfasst: Mittwoch 7. November 2018, 22:43
von __blackjack__
@Felix92: Erst mal ist es komisch das Deine Klasse von `QGridLayout` erbt. Das macht keinen Sinn.
Dann sollte man keine Widgets mit `move()` absolut platzieren sondern auch dafür Layoutklassen verwenden. Eventuell mit zusätzlichen Widgets als Container.
Auf die Buttons kannst Du zugreifen in dem Du Dir die Objekte in irgendeiner Datenstruktur merkst. Zum Beispiel eine verschachtelte Liste, die die 2D-Struktur wiederspiegelt, oder ein Wörterbuch das Tupel mit den Koordinaten auf die Button-Objekte abbildet.
Die Implementierung für den "Restart"-Button ist so gar keine gute Idee. Versuche das sauber innerhalb des gleichen Programms zu lösen statt das Programm immer wieder aus sich selbst heraus als neues *zusätzliches* Programm zu starten.
Re: Zugriff auf Widget aus Gridlayout - Problem
Verfasst: Mittwoch 7. November 2018, 23:18
von Felix92
Ok danke erstmal für eure Antworten allerdings muss ich sagen verstehe ich den Zugriff auf einzelne Elemente im Grid nicht so ganz.
Mein Gedanke war:
(Das ganze als Eventhandler)
wenn button aus grid geklickt dann:
Setze farbe für (button, x, y) auf schwarz
// selbes für die Buttons daneben drüber und drunter
Wenn button schwarz dann setze farbe auf weiß
Geht das in python nicht das ich direkt z.B. auf den Button an position(0, 0) zugreife ?
Und dann sage if button(0, 0) clicked set...
Weil die Elemente müssten nach dem erzeugen ja eigentlich alle vorhanden sein !?
Und für den Abstand hatte ich probiert:
grid_layout.setSpacing(0) allerdings gibt's dort nur ein paar hinter die Ohren

Re: Zugriff auf Widget aus Gridlayout - Problem
Verfasst: Mittwoch 7. November 2018, 23:36
von __deets__
Jein. Natürlich geht das:
http://doc.qt.io/qt-5/qgridlayout.html#itemAtPosition
Ist halt nur ne doofe Idee. Denn wenn du jetzt feststellst, das du aus Layout-Gründen deinen Button nochmal in ein anderes Widget wickeln musst, dann bleibt der Code nach unserer Methode stabil. Aber nach deiner musst du lauter stellen anfassen. Darum macht man das so nicht.
Mit dem Layout kann ich dir nur empfehlen mit dem Designer rumzuspielen, bis es klappt.
Re: Zugriff auf Widget aus Gridlayout - Problem
Verfasst: Freitag 9. November 2018, 19:20
von __blackjack__
@Felix92: Ich habe mir mal eben spasseshalber JavaFX (8) angeschaut, und da *muss* man sich das ja parallel als Datenstruktur vorhalten. Oder übersehe ich da etwas?
Re: Zugriff auf Widget aus Gridlayout - Problem
Verfasst: Sonntag 11. November 2018, 20:46
von __blackjack__
Ich habe das mal spasseshalber mit Jython und JavaFX implementiert:
Code: Alles auswählen
#!/usr/bin/env jython
# coding: utf-8
from __future__ import absolute_import, division, print_function
import sys
from functools import partial
from javafx.application import Application
from javafx.scene import Scene
from javafx.scene import control
from javafx.scene.layout import TilePane
class FXTest(Application):
SIZE = 3
BACKGROUND_COLOR_BLACK = '-fx-background-color: black;'
BACKGROUND_COLOR_WHITE = '-fx-background-color: white;'
STYLE_TO_INVERTED_STYLE = {
BACKGROUND_COLOR_BLACK: BACKGROUND_COLOR_WHITE,
BACKGROUND_COLOR_WHITE: BACKGROUND_COLOR_BLACK,
}
def __init__(self):
self.cells = [[None] * self.SIZE for _ in xrange(self.SIZE)]
def start(self, stage):
pane = TilePane(prefColumns=self.SIZE)
for i in xrange(self.SIZE):
for j in xrange(self.SIZE):
button = control.Button(
str(i * self.SIZE + j),
onAction=lambda event, y=i, x=j: self.invert_cross(x, y),
style=self.BACKGROUND_COLOR_WHITE,
)
pane.children.add(button)
self.cells[i][j] = button
stage.scene = Scene(pane)
stage.show()
def invert(self, x, y):
if 0 <= x < self.SIZE and 0 <= y < self.SIZE:
cell = self.cells[y][x]
cell.style = self.STYLE_TO_INVERTED_STYLE[cell.style]
def invert_cross(self, x, y):
self.invert(x, y)
self.invert(x - 1, y)
self.invert(x + 1, y)
self.invert(x, y - 1)
self.invert(x, y + 1)
def main():
FXTest.launch(FXTest().class, sys.argv)
if __name__ == '__main__':
main()
Ich wüsste nicht wie man bei JavaFX (sinnvoll) darum herum kommen würde sich das wie hier in `self.cells` in einer 2D-Datenstruktur zu merken. Denn von dem `TilePane` kann man nur eine flache Liste mit den angezeigten `Node`-Objekten geben lassen.
Re: Zugriff auf Widget aus Gridlayout - Problem
Verfasst: Montag 12. November 2018, 19:55
von Felix92
@_blackjack_ ich hätte das in Java (FX) mit dem SceneBuilder umgesetzt wäre meiner Meinung nach die schnellste und sauberste Angehensweise den Buttons eine/mehrere ID"s" zuweisen und die Methode/n für die Buttons schreiben ID implementieren fertig, da man somit den ganzen GUI Code gleich noch in fxml auslagert wäre in Python vermutlich auch einfacher als ich es anstelle allerdings habe ich dort noch nicht so viel Erfahrung

.
Ok ein wenig bin ich weiter gekommen hätte dann gleich mal noch 2 Fragen .D
Und zwar habe ich probiert das die Farbe der Buttons nur geändert wird solange Sie sich im Grid befinden und alles andere ignoriert wird allerdings klappt das nicht so wie ich dachte führt immer zum Error da ich Buttons die nicht vorhanden sind bzw. ausserhalb des Grids liegen würden "anspreche" wie könnte ich das lösen !?
Über if/else habe ich es leider nicht hinbekommen also wenn loc[0] <0 do: pass else setBackgroundColor....etc.
Und 2tens wäre wie kann ich in Python die Farbe von Buttons vergleichen ?
Danke für eure Hilfe
MfG Felix
Hier der Code:
Code: Alles auswählen
import sys
import subprocess
from PyQt5.QtWidgets import (QWidget, QGridLayout, QPushButton, QApplication, QSizePolicy,)
class basicWindow(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle('Game')
button1 = QPushButton("3 x 3", self)
button1.move(106, 115)
button1.resize(38, 30)
button1.setStyleSheet("background-color: grey")
button1.clicked.connect(self.button1clicked)
button2 = QPushButton("4 x 4", self)
button2.move(153, 115)
button2.resize(38, 30)
button2.setStyleSheet("background-color: grey")
button2.clicked.connect(self.button2clicked)
def button1clicked(self):
grid_layout = QGridLayout()
self.setLayout(grid_layout)
for x in range(3):
for y in range(3):
button = QPushButton()
policy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
button.setSizePolicy(policy)
button.setStyleSheet("background-color: white")
grid_layout.addWidget(button, x, y)
button.clicked.connect(self.buttonColor)
button3 = QPushButton("Restart", self)
grid_layout.addChildWidget(button3)
button3.move(125, 0)
button3.resize(50, 20)
button3.setStyleSheet("background-color: grey")
button3.clicked.connect(self.button3clicked)
def button2clicked(self):
grid_layout = QGridLayout()
self.setLayout(grid_layout)
for x in range(4):
for y in range(4):
button = QPushButton()
policy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
button.setSizePolicy(policy)
button.setStyleSheet("background-color: white")
grid_layout.addWidget(button, x, y)
button.clicked.connect(self.buttonColor)
button3 = QPushButton("Restart", self)
grid_layout.addChildWidget(button3)
button3.move(125, 0)
button3.resize(50, 20)
button3.setStyleSheet("background-color: grey")
button3.clicked.connect(self.button3clicked)
def buttonColor(self):
button = self.sender()
index = self.layout().indexOf(button)
loc = self.layout().getItemPosition(index)
b1 = self.layout().itemAtPosition(loc[0], loc[1]).widget()
b1.setStyleSheet("background-color: black")
b2 = self.layout().itemAtPosition(loc[0] + 1, loc[1]).widget()
b3 = self.layout().itemAtPosition(loc[0], loc[1] - 1).widget()
b4 = self.layout().itemAtPosition(loc[0] - 1, loc[1]).widget()
b5 = self.layout().itemAtPosition(loc[0], loc[1] + 1).widget()
if loc[0] < 0:
pass
else:
b4.setStyleSheet("background-color: black")
if loc[0] > 2:
pass
else:
b2.setStyleSheet("background-color: black")
if loc[1] < 0:
pass
else:
b3.setStyleSheet("background-color: black")
if loc[1] > 2:
pass
else:
b5.setStyleSheet("background-color: black")
#print(index, loc[0], loc[1])
#todo wenn button aus grid gedrückt setze diesen / x-1 / x+1 /y-1 /y+1 auf black
#todo wenn button schon schwarz setze ihn auf weiß
def button3clicked(self):
self.close()
subprocess.call("python" + " game.py", shell=True)
if __name__ == '__main__':
app = QApplication(sys.argv)
window = basicWindow()
window.setStyleSheet("background-color: orange")
window.setFixedSize(300, 300)
window.show()
sys.exit(app.exec_())
Re: Zugriff auf Widget aus Gridlayout - Problem
Verfasst: Montag 12. November 2018, 19:56
von Felix92
Der Code worum es geht:
Code: Alles auswählen
def buttonColor(self):
button = self.sender()
index = self.layout().indexOf(button)
loc = self.layout().getItemPosition(index)
b1 = self.layout().itemAtPosition(loc[0], loc[1]).widget()
b1.setStyleSheet("background-color: black")
b2 = self.layout().itemAtPosition(loc[0] + 1, loc[1]).widget()
b3 = self.layout().itemAtPosition(loc[0], loc[1] - 1).widget()
b4 = self.layout().itemAtPosition(loc[0] - 1, loc[1]).widget()
b5 = self.layout().itemAtPosition(loc[0], loc[1] + 1).widget()
if loc[0] < 0:
pass
else:
b4.setStyleSheet("background-color: black")
if loc[0] > 2:
pass
else:
b2.setStyleSheet("background-color: black")
if loc[1] < 0:
pass
else:
b3.setStyleSheet("background-color: black")
if loc[1] > 2:
pass
else:
b5.setStyleSheet("background-color: black")
#print(index, loc[0], loc[1])
#todo wenn button aus grid gedrückt setze diesen / x-1 / x+1 /y-1 /y+1 auf black
#todo wenn button schon schwarz setze ihn auf weiß
Re: Zugriff auf Widget aus Gridlayout - Problem
Verfasst: Montag 12. November 2018, 20:35
von __blackjack__
@Felix92: Wie gesagt: Ich würde eine eigene Datenstruktur erstellen statt das aus der GUI wieder irgendwie raus zu popeln. Und ich würde auch zusätzlich die Programmlogik noch unabhängig von der GUI machen. Du veranstaltest da viel zu viel in der GUI statt das die einfach nur zum anzeigen und entgegennehmen von Benutzerinteraktion ist, speicherst Du Daten in der GUI. Dafür ist die nicht gedacht.
Wenn man einen ``if``- oder einen ``else``-Zweig hat in dem nur ein ``pass`` steht, dann macht man offensichtlich etwas falsch, denn so etwas kann man *immer* vermeiden.
Wie man testet ob Koordinaten innerhalb bestimmter Grenzen liegen, habe ich in meinem Code zu stehen. Ganz einfach ``if`` und Vergleiche.