Kivy GUi mit mehreren Tabs. Aktuellen tab fokussieren

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
Alsen
User
Beiträge: 12
Registriert: Dienstag 6. November 2018, 12:50

Guten Tag,

ich bin grad dabei eine GUI in Kivy zu schreiben. Diese ist relativ klein und hat 5 Buttons, einen Slider und ein Canvas(aktuelle noch Button).
Bisher habe ich einen Standard tab in dem ein Button ist, der eine Funktion auslöst, die mir einen zusätzlichen Tab öffnet mit oben besagten Buttons und Canvas.
Siehe bilder:
https://ibb.co/jUnm0V
https://ibb.co/dJKS7A

Nun hätte ich gerne wenn ich den Button set focus drücke, dass der slider den Wert 0 annimmt. Das klappt auch wenn es nur einen Tab gibt. Sobald ich zwei tabs habe, und den Button setfocus aus dem Tab 1 drücke verändert sich jedoch der slider aus Tab 2.
Ich dachte das könnte ich umgehen, wenn ich jedem Widget eines Tabs die ID übergebe, die der Länge der Liste der Tabs entspricht. Sprich alle widgets des ersten Tabs haben die ID 1 und die Widgets des zweiten Tabs die ID 2. Das klappt auch soweit.
Wenn ich nun per bind eine Methode an ein Widget knüpfe, wird ja auch das Objekt übergeben. Also habe ich die ID des übergebenen Objekts also des Buttons aus Tab 1 der ID des Sliders übergeben, sodass also auch der Slider des Tab 1 addressiert wird, was jedoch nicht klappt.
Wie könnte man sowas bewerkstelligen ?

Besten Dank im vorraus

Anbei hier der Code:

class RootWidget(BoxLayout):

def __init__(self,**kwargs):
super(RootWidget, self).__init__(**kwargs)
self.liste=[]
self.tp=TabbedPanel(do_default_tab=False)
self.add_widget(self.tp)
self.thd=TabbedPanelItem(text='+')
self.tp.add_widget(self.thd)
self.b_add=Button(text='add tab')
self.thd.add_widget(self.b_add)
self.b_add.bind(on_press=self.addtab)


def addtab(self, test=None):
self.tp.add_widget(self.createtabs())

def createtabs(self):
print('Button is pressed')
self.th=TabbedPanelItem(text='Tab '+str(len(self.tp.tab_list)),id=str(len(self.tp.tab_list)))
self.th.focus=self.th

#self.tp.add_widget(self.th)
self.Box=BoxLayout(orientation='vertical',id=str(len(self.tp.tab_list)))
self.BoxL=BoxLayout(id=str(len(self.tp.tab_list)))
self.BoxR=GridLayout(cols=6,id=str(len(self.tp.tab_list)))
self.th.add_widget(self.Box)
self.Box.add_widget(self.BoxR)
self.Box.add_widget(self.BoxL)


#should be the matplotlib canvas
self.b2=Button(text='btn 2',id=str(len(self.tp.tab_list)))

self.b_convert=Button(text='convert .nsdx to .txt',id=str(len(self.tp.tab_list)))
self.b_load=Button(text='load data',id=str(len(self.tp.tab_list)))
self.b_setfocus=Button(text='set focus',id=str(len(self.tp.tab_list)))
self.b_calcbeam=Button(text='calculate\nbeamproperties',id=str(len(self.tp.tab_list)))
self.b_export=Button(text='export plot',id=str(len(self.tp.tab_list)))
self.s_slider=Slider(id=str(len(self.tp.tab_list)),min=0,max=100,value=50)

#buttons
self.BoxL.add_widget(self.b2)
self.BoxR.add_widget(self.b_convert)
self.BoxR.add_widget(self.b_load)
self.BoxR.add_widget(self.b_setfocus)
self.BoxR.add_widget(self.b_calcbeam)
self.BoxR.add_widget(self.b_export)
self.BoxR.add_widget(self.s_slider)

#bind functions
self.b_convert.bind(on_press=self.callback)
self.b_setfocus.bind(on_press=self.setfocus)

return self.th

def setfocus(self,actualbutton):
actualbutton.id
self.s_slider.id=actualbutton.id
self.s_slider.value=0

return
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Bitte benutz die Code-Tags, so ist das nicht zu entziffern.
Alsen
User
Beiträge: 12
Registriert: Dienstag 6. November 2018, 12:50

Guten Tag,

ich bin grad dabei eine GUI in Kivy zu schreiben. Diese ist relativ klein und hat 5 Buttons, einen Slider und ein Canvas(aktuelle noch Button).
Bisher habe ich einen Standard tab in dem ein Button ist, der eine Funktion auslöst, die mir einen zusätzlichen Tab öffnet mit oben besagten Buttons und Canvas.
Siehe bilder:
https://ibb.co/jUnm0V
https://ibb.co/dJKS7A

Nun hätte ich gerne wenn ich den Button set focus drücke, dass der slider den Wert 0 annimmt. Das klappt auch wenn es nur einen Tab gibt. Sobald ich zwei tabs habe, und den Button setfocus aus dem Tab 1 drücke verändert sich jedoch der slider aus Tab 2.
Ich dachte das könnte ich umgehen, wenn ich jedem Widget eines Tabs die ID übergebe, die der Länge der Liste der Tabs entspricht. Sprich alle widgets des ersten Tabs haben die ID 1 und die Widgets des zweiten Tabs die ID 2. Das klappt auch soweit.
Wenn ich nun per bind eine Methode an ein Widget knüpfe, wird ja auch das Objekt übergeben. Also habe ich die ID des übergebenen Objekts also des Buttons aus Tab 1 der ID des Sliders übergeben, sodass also auch der Slider des Tab 1 addressiert wird, was jedoch nicht klappt.
Wie könnte man sowas bewerkstelligen ?

Besten Dank im vorraus

Anbei hier der Code:

Code: Alles auswählen

class RootWidget(BoxLayout):

	def __init__(self,**kwargs):
		super(RootWidget, self).__init__(**kwargs)
		self.liste=[]
		self.tp=TabbedPanel(do_default_tab=False)
		self.add_widget(self.tp)
		self.thd=TabbedPanelItem(text='+')
		self.tp.add_widget(self.thd)
		self.b_add=Button(text='add tab')
		self.thd.add_widget(self.b_add)
		self.b_add.bind(on_press=self.addtab)


	def addtab(self, test=None):
		self.tp.add_widget(self.createtabs())

	def createtabs(self):
		print('Button is pressed')
		self.th=TabbedPanelItem(text='Tab '+str(len(self.tp.tab_list)),id=str(len(self.tp.tab_list)))
		self.th.focus=self.th

		#self.tp.add_widget(self.th)
		self.Box=BoxLayout(orientation='vertical',id=str(len(self.tp.tab_list)))
		self.BoxL=BoxLayout(id=str(len(self.tp.tab_list)))
		self.BoxR=GridLayout(cols=6,id=str(len(self.tp.tab_list)))
		self.th.add_widget(self.Box)
		self.Box.add_widget(self.BoxR)
		self.Box.add_widget(self.BoxL)


		#should be the matplotlib canvas
		self.b2=Button(text='btn 2',id=str(len(self.tp.tab_list)))

		self.b_convert=Button(text='convert .nsdx to .txt',id=str(len(self.tp.tab_list)))
		self.b_load=Button(text='load data',id=str(len(self.tp.tab_list)))
		self.b_setfocus=Button(text='set focus',id=str(len(self.tp.tab_list)))
		self.b_calcbeam=Button(text='calculate\nbeamproperties',id=str(len(self.tp.tab_list)))
		self.b_export=Button(text='export plot',id=str(len(self.tp.tab_list)))
		self.s_slider=Slider(id=str(len(self.tp.tab_list)),min=0,max=100,value=50)

		#buttons
		self.BoxL.add_widget(self.b2)
		self.BoxR.add_widget(self.b_convert)
		self.BoxR.add_widget(self.b_load)
 		self.BoxR.add_widget(self.b_setfocus)
		self.BoxR.add_widget(self.b_calcbeam)
		self.BoxR.add_widget(self.b_export)
		self.BoxR.add_widget(self.s_slider)

		#bind functions
		self.b_convert.bind(on_press=self.callback)
		self.b_setfocus.bind(on_press=self.setfocus)

		return self.th

	def setfocus(self,actualbutton):
		actualbutton.id
		self.s_slider.id=actualbutton.id
		self.s_slider.value=0

		return
Zuletzt geändert von Alsen am Donnerstag 22. November 2018, 09:34, insgesamt 1-mal geändert.
Alsen
User
Beiträge: 12
Registriert: Dienstag 6. November 2018, 12:50

__deets__ hat geschrieben: Mittwoch 21. November 2018, 16:58 Bitte benutz die Code-Tags, so ist das nicht zu entziffern.
könntest du dann meinen vorherigen Kommentar löschen. Ich finde leider keine Option das selber zu bewerkstellige.
Besten Dank
Sirius3
User
Beiträge: 18268
Registriert: Sonntag 21. Oktober 2012, 17:20

@Alsen: trotz code-Tags sind die Einrückungen kaputt. Hier gibt es einen Vorschau-Knopf, mit dem man sehen kann, ob der Post auch richtig dargestellt wird.

Zum Problem: Du überschreibst alle Attribute Deiner Klasse beim Erzeugen eines neuen Tabs. Du mußt für die Tabs eine eigene Klasse schreiben und die Tabs z.B. in einer Liste in RootWidget speichern.
Alsen
User
Beiträge: 12
Registriert: Dienstag 6. November 2018, 12:50

Sirius3 hat geschrieben: Donnerstag 22. November 2018, 09:23 @Alsen: trotz code-Tags sind die Einrückungen kaputt. Hier gibt es einen Vorschau-Knopf, mit dem man sehen kann, ob der Post auch richtig dargestellt wird.

Zum Problem: Du überschreibst alle Attribute Deiner Klasse beim Erzeugen eines neuen Tabs. Du mußt für die Tabs eine eigene Klasse schreiben und die Tabs z.B. in einer Liste in RootWidget speichern.
so habe es jetzt eingerückt. Danke war mir gar nicht aufgefallen.

Also wenn ich jetzt ein Objekt meiner Klasse tab, was einem TabbedPanelItem entspricht an die Klasse RootWidget übergeben sollte und da in einer Liste speichere. Soll ich dann über eine For -Schleife die Objekte in der Liste an mein TabbedPanel tp anhängen?
Wenn das so gedacht ist verstehe ich dennoch nicht wie die Buttons dann eindeutig in den Tabs addressiert werden.
Außerdem ist es doch schon so wenn ich die Methode createtabs aufrufe über die Methode addtabs, dass ein Objekt der Klasse TabbedpanelItem also mein th an die Klasse Rootwidget übergeben wird bzw das alles ja in dieser Klasse passiert. Verstehe leider nicht ganz den Vorteil einer weiteren Klasse in diesem Fall. Die ID der erstellten Tabs und der darin liegenden Widgets ist ja bereits eindeutig. Also Tab 1 hat auch die ID 1 ,da diese sich nach der Länge der Tab_Liste orientiert, welche automatisch im hintergrund von Kivy angelegt wird.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Du beziehst dich an diversen Stellen auf Attribute, die du in createtabs anlegst. ZB self.s_slider. Wenn du jetzt 20 Tabs anlegst, dann zeigt self.s_slider immer nur auf den jeweils letzten. Auf die anderen kannst du nicht mehr zugreifen. Damit wird dann setfocus immer nur den letzten Tab erreichen.

Stattdessen musst du einen callback erzeugen, der das konkrete Objekt das er in den Focus ruecken soll kennt. ZB mit functools.partial.

Ganz generell legst du vieeeeel zu viel Zustand auf self an. Die ganzen Boxen, layouts etc. haben da ueberaupt nichts verloren. Die sind Teil deiner Widget-Hiearchie, und es gibt keinen Grund, die alle auf self. verfuegbar zu machen.
Sirius3
User
Beiträge: 18268
Registriert: Sonntag 21. Oktober 2012, 17:20

@Alsen: dass Du irgendwelche IDs verteilst, ist dem Programm ziemlich egal. In setfocus überschreibst Du sogar die ID Deines Sliders, ohne das das irgendetwas bewirkt; das Attribut s_slider zeigt immer noch auf den zuletzt angelegten Slider. Alle vorhergenenden Tabs sind für Dich nicht mehr erreichbar.

Jeder Tab ein eigenes in sich abgeschlossenes Objekt. Das Knöpfe hat und Methoden, die auf diese Knöpfe reagieren. Es ist also ganz natürlich, das auch als Klasse zu implementieren. Dann ist auch klar, welcher Knopf zu welchem Slider gehört, und Du kannst Dir die IDs sparen.
Antworten