Wahrscheinlich einfaches Problem

Programmierung für GNOME und GTK+, GUI-Erstellung mit Glade.
gugugs
User
Beiträge: 113
Registriert: Dienstag 30. Dezember 2008, 12:38

Dienstag 30. Dezember 2008, 12:43

Ich hab ein Fenster, in dem 2 RadioButton sind.

Und zwar, würde ich gern, das wenn z.B. : radiobutton1 aktiv ist, dass ich dann 4 entrys habe und sobald ich auf radiobutton2 klicke dass dann nur 3 entrys da sind, und bei radiobutton1 halt wieder 4 entrys

Wie stelle ich das am besten an?

Ich habe mir erst gedacht, das wenn Radio Button 1 toggled wurde, das er dann in eine Funktion geht, in der er die 4 entrys in eine box macht, aber wie bekomme ich die dann im Fenster angezeigt?

Und wie schaffe ich es dann, das wenn Button 2 toggled wurde, das er die 4 entrys aus der box löscht und 3 wieder herein schreibt?


Es handelt sich um GTK

ich hatte mir das jetzt so vorgestellt:
der abschnitt in dem ich das vor habe:

Code: Alles auswählen


class umfang:

	def change(self, widget, data):
		if data=="radio1":
			entry1=gtk.Entry()
			entry2=gtk.Entry()
			entry3=gtk.Entry()
			entry4=gtk.Entry()
			vbox.pack_start(entry1)
			vbox.pack_start(entry2)
			vbox.pack_start(entry3)
			vbox.pack_start(entry4)
		if data=="radio2":
			entry1=gtk.Entry()
			entry2=gtk.Entry()
			entry3=gtk.Entry()
			vbox.pack_start(entry1)
			vbox.pack_start(entry2)
			vbox.pack_start(entry3)
			
			

	
	def __init__(self):
		window=gtk.Window(gtk.WINDOW_TOPLEVEL)
		window.set_title("Rechner - Umfang")
		window.set_border_width(0)

		vbox=gtk.VBox(False, 0)
		window.add(vbox)

		frame=gtk.Frame("Erklaerung:")
		label=gtk.Label("Waehlen sie zunaechst ob Viereck oder Dreieck.\n"
				"Danach geben sie entweder 4 Informationen fuer das Viereck\n"
				"oder 3 fuer das Dreieck.")
		frame.add(label)
		vbox.pack_start(frame)

		radio1=gtk.RadioButton(None, "Viereck")
		radio1.connect("toggled", self.change, "radio1")
		vbox.pack_start(radio1)

		radio2=gtk.RadioButton(radio1, "Dreieck")
		radio2.connect("toggled", self.change, "radio2")
		vbox.pack_start(radio2)

		window.show_all()


Aber so funktioniert das nicht, allein schon, weil dort, vbox ja noch nicht definiert ist. Aber ich weis nicht, wie ich das sonst anstellen sollte.
Weis irgendjemand wie mir zu helfen ist? Es kann auch ganz anders sein, hauptsache das Prinzip wird verwirklicht

Bitte um jede Hilfe
Benutzeravatar
Trundle
User
Beiträge: 591
Registriert: Dienstag 3. Juli 2007, 16:45

Dienstag 30. Dezember 2008, 14:07

Ich würde einfach ein `gtk.Notebook` nehmen, da hat dann einfach jede geometrische Figur eine eigene Seite. Und PyGtk kann auch Umlaute anzeigen, wenn man Unicode-Strings (oder UTF8-kodierte Bytestrings) übergibt.

Ansonsten ist das Scope-Problem eher grundsätzlicher Natur als ein Gtk-Problem, also vielleicht solltest du dich erst an GUI-Programmierung wagen, wenn du an einem soliden Basiswissen über Python verfügst.
"Der Dumme erwartet viel. Der Denkende sagt wenig." ("Herr Keuner" -- Bertolt Brecht)
Dauerbaustelle
User
Beiträge: 996
Registriert: Mittwoch 9. Januar 2008, 13:48

Mittwoch 31. Dezember 2008, 01:02

Hi gugugs,

du hast wohl die Benutzung von Klasse nicht ganz verstanden.

Wenn ich eine Variable als klassenübergreifend definieren will, dann erstelle ich sie "auf" der Instanz:

Code: Alles auswählen

[...]
def do_bla(self):
    self.myvar = "foo"
[...]
Eine Variable, die nicht in der Instanz erstellt wurde, wird nach Ende einer Funktion wieder gelöscht.

Kleines Beispiel:

Code: Alles auswählen

In [2]:
class Blah:
    def __init__(self):
        self.blah1 = "foo"
        blah2 = "bar"
        self.do_blah()
    def do_blah(self):
         self.blah3 = "blubb"
         blah4 = "blah"

In [8]: b = Blah()

In [9]: b.blah1
Out[9]: 'foo'

In [10]: b.blah2
---------------------------------------------------------------------------
<type 'exceptions.AttributeError'>: Blah instance has no attribute 'blah2'

In [11]: b.blah3
Out[11]: 'blubb'

In [12]: b.blah4
---------------------------------------------------------------------------
<type 'exceptions.AttributeError'>: Blah instance has no attribute 'blah4'
Du machst also Variablen wie deine Fenster-Elemente klassenübergreifend nutzbar, sodass du sie auch in anderen Funktionen als __init__() benutzen kannst.

PS: Dadurch musst du dann auch in den connect-Funktionen das "data"-Argument nicht mehr mitgeben, weil du einfach abfragst, ob das den-Event-auslösende Widget das erste oder zweite war:

Code: Alles auswählen

    def change(self, widget):
        if widget==self.radio1:
            entry1=gtk.Entry()
            entry2=gtk.Entry()
            entry3=gtk.Entry()
            entry4=gtk.Entry()
            vbox.pack_start(entry1)
            vbox.pack_start(entry2)
            vbox.pack_start(entry3)
            vbox.pack_start(entry4)
        elif widget==self.radio2:
            entry1=gtk.Entry()
            entry2=gtk.Entry()
            entry3=gtk.Entry()
            vbox.pack_start(entry1)
            vbox.pack_start(entry2)
            vbox.pack_start(entry3)
außerdem könnte man die Funktion noch ein wenig verbessern - du führst in beiden Fällen identischen Code aus, das ist so, als ob würdest du sagen "Wenn du hier zwei Äpfel hast springe einmal im Kreis und wenn nicht tus trotzdem":

Code: Alles auswählen

    def change(self, widget):
            entry1=gtk.Entry()
            entry2=gtk.Entry()
            entry3=gtk.Entry()
            vbox.pack_start(entry1)
            vbox.pack_start(entry2)
            vbox.pack_start(entry3)
        if widget==self.radio1:
            entry4=gtk.Entry()
            vbox.pack_start(entry4)
Benutzeravatar
cofi
Moderator
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Mittwoch 31. Dezember 2008, 08:10

Dauerbaustelle hat geschrieben:Wenn ich eine Variable als klassenübergreifend definieren will, dann erstelle ich sie "auf" der Instanz
Nicht ganz ;) Wenn ich sie KLASSENübergreifend haben will, dann definier ich sie auch in der Klasse - nicht in einer Funktion(!), denn sonst ist sie nicht lokal zur Klasse, sondern lokal zur Funktion. Will ich sie INSTANZübergreifend benutzen, dann definiere ich sie auf der Instanz ;)
Dauerbaustelle hat geschrieben:Eine Variable, die nicht in der Instanz erstellt wurde, wird nach Ende einer Funktion wieder gelöscht.
Auch wieder nicht ganz ;) Ist die "Variable" lokal zur Funktion, dann ja, lokal zur Klasse bzw einem anderen äußeren Scope - bis einschliesslich Modulebene, dann nicht ;)

Soo ich werf mal 20 cent in die Klugscheisserkasse :oops:
Dauerbaustelle
User
Beiträge: 996
Registriert: Mittwoch 9. Januar 2008, 13:48

Mittwoch 31. Dezember 2008, 11:29

-.-

Dir ist aber schon klar, dass wir es hier mit einem Einsteiger zu tun haben?!

-______________________-
Benutzeravatar
cofi
Moderator
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Mittwoch 31. Dezember 2008, 15:18

Naja das heisst aber nicht, dass die Information falsch sein darf, gerade bei einem Anfänger der das ja nicht erkennen kann, besonders wichtig.
Und der Schwierigkeitsgrad das zu verstehen erhöht sich auch nicht sonderlich.
gugugs
User
Beiträge: 113
Registriert: Dienstag 30. Dezember 2008, 12:38

Donnerstag 1. Januar 2009, 21:03

Vielen Dank für alle Beiträge, hab jetzt wieder ein wenig mehr verstanden. Hab mir auch das mit den lokalen und globalen Variablen und das Instanzen Thema etwas mehr durchgelesen. Habe das ganze aber jetzt sowieso anders gemacht, mit einem NoteBook war es dann doch einfacher.


Jetzt stehe ich leider schon wieder vor einem neuen Problem, wenn man mir nun da noch helfen könnte, wär echt super. Und zwar, warum kommt bei diesem kleinen Berreich, die Fehlermeldung:

AttributeError: 'NoneType' object has no attribute 'draw_line'


Berreich:

Code: Alles auswählen

		window = gtk.Window(gtk.WINDOW_TOPLEVEL)
		window.set_title("Drawing Area Example")
		window.connect("destroy", lambda w: gtk.main_quit())
		window.set_size_request(400, 300)
		area = gtk.DrawingArea()
		area.show()
		area.set_size_request(400, 300)
		drawable = area.window
		table = gtk.Table(2,2)
		hruler = gtk.HRuler()
		vruler = gtk.VRuler()
		hruler.set_range(0, 400, 0, 400)
		vruler.set_range(0, 300, 0, 300)
		table.attach(hruler, 1, 2, 0, 1, yoptions=0)
		table.attach(vruler, 0, 1, 1, 2, xoptions=0)

		style = area.get_style()
        	gc = style.fg_gc[gtk.STATE_NORMAL]
		drawable.draw_line(gc, 10, 30, 20, 40)

		window.add(table)

		window.show_all()
Benutzeravatar
Trundle
User
Beiträge: 591
Registriert: Dienstag 3. Juli 2007, 16:45

Donnerstag 1. Januar 2009, 21:37

Widgets müssen erst "realized" sein (hat da jemand spontan ein schöne Übersetzung dafür?) sein, bevor sie mit einem `gtk.gdk.Window` verbunden sind. Und das geschieht erst, wenn `realize()` aufgerufen wird, und dazu muss das Widget in einem Toplevel-Window (sichtbar) sein. IdR geschieht der Aufruf indirekt (bspw. durch einen Aufruf von `show()`). Vorher gibt ``widget.window`` eben `None` zurück, wie in deinem Code zu sehen ist.

Außerdem genügt es nicht, nur einmal zu zeichnen. Wenn z.B. die Größe verändert wird oder ein anderes Fenster über das Fenster geschoben wird oder das Fenster minimiert und wieder maximiert wird, muss ja wieder neu gezeichnet werden. Deshalb solltest du den Zeichencode in eine Funktion stecken und diese mit dem ``expose-event``-Signal verbinden. Dann wird jedes Mal die Funktion aufgerufen, wenn das Widget sich neu zeichnen soll.

Desweiteren finde ich es wesentlich angenehmer mit Cairo zu arbeiten als mit den ganzen GTK+-Zeichenfunktionen.
"Der Dumme erwartet viel. Der Denkende sagt wenig." ("Herr Keuner" -- Bertolt Brecht)
Dauerbaustelle
User
Beiträge: 996
Registriert: Mittwoch 9. Januar 2008, 13:48

Donnerstag 1. Januar 2009, 22:47

Trundle, du hast glaube ich vergessen zu erwähnen, dass eben dieses draw_line erst funktioniert, wenn die Widgets ge-realized wurden (was du ja erwähnt hattest).

@gugugs, das heißt ganze einfach, dass sich das Widget schon IM Fenster befinden muss. Dies tut es allerdings nicht, da sein Parent (das gtk.Table-Widget) noch nicht hinzugefügt wurde.

Das heißt: Zuerst window.add(table) und dann ...draw_blubb.

Außerdem empfiehlt es sich wie bereits erwähnt die Widgets auf der Instanz zu erstellen, also wie bereits erklärt mit self.foo und self.bar anzusprechen.

Grüße
Benutzeravatar
Trundle
User
Beiträge: 591
Registriert: Dienstag 3. Juli 2007, 16:45

Donnerstag 1. Januar 2009, 23:09

@Dauerbaustelle
Ich habe geschrieben, dass dann ``widget.window`` einen None-Typ zurückgibt, woraus sich ergibt, dass eben `drawable` ein None-Typ ist und kein `gtk.gdk.Window`. Dass man weiß, dass `None` keine `draw_line`-Methode hat, davon gehe ich eigentlich aus.

Außerdem muss erst das Widget selbst und *sämtliche* Container (also auch das Toplevel-Fester) sichtbar sein, bevor überhaupt ein `gtk.gdk.Window` mit dem Widget verbunden ist. Es bringt also schlicht und ergreifend nichts, "zuerst window.add(table) und dann ...draw_blubb" zu machen, weil davon das Fenster immer noch nicht angezeigt wird, mal ganz davon abgesehen, dass die Area im ganzen Code in keinen Container gesteckt wird. Und selbst wenn es funktionieren würde, wäre es immer noch falsch. Der richtige Weg ist es, nach einem Expose-Event neu zu zeichen.
"Der Dumme erwartet viel. Der Denkende sagt wenig." ("Herr Keuner" -- Bertolt Brecht)
gugugs
User
Beiträge: 113
Registriert: Dienstag 30. Dezember 2008, 12:38

Donnerstag 1. Januar 2009, 23:12

Oke schon mal vielen Dank.

Um den Umgang mit GTK zu lernen, verfolge ich das dieses Tutorial:
http://www.pygtk.org/pygtk2tutorial/

Bis jetzt hab ich dort auch alles verstanden, und die Beispiele wurden sehr verständlich gemacht, doch bei dem Beispiele bei 12.2:

http://www.pygtk.org/pygtk2tutorial/sec ... thods.html

bei dem es genau darum geht, wovon gerade die Rede ist, verstehe ich leider überhaupt nicht. Wie insgesammte Aufbau ist, und wie die Funktionen UNTEN funktionieren, verstehe ich auch. Doch der Anfang, wo der Aufbau des Fensters ist, da habe ich große Probleme in diesem Berreich:

Code: Alles auswählen

    def __init__(self):
        window = gtk.Window(gtk.WINDOW_TOPLEVEL)
        window.set_title("Drawing Area Example")
        window.connect("destroy", lambda w: gtk.main_quit())
        self.area = gtk.DrawingArea()
        self.area.set_size_request(400, 300)
        self.pangolayout = self.area.create_pango_layout("")
        self.sw = gtk.ScrolledWindow()
        self.sw.add_with_viewport(self.area)
        self.table = gtk.Table(2,2)
        self.hruler = gtk.HRuler()
        self.vruler = gtk.VRuler()
        self.hruler.set_range(0, 400, 0, 400)
        self.vruler.set_range(0, 300, 0, 300)
        self.table.attach(self.hruler, 1, 2, 0, 1, yoptions=0)
        self.table.attach(self.vruler, 0, 1, 1, 2, xoptions=0)
        self.table.attach(self.sw, 1, 2, 1, 2)
        window.add(self.table)
        self.area.set_events(gtk.gdk.POINTER_MOTION_MASK |
                             gtk.gdk.POINTER_MOTION_HINT_MASK )
        self.area.connect("expose-event", self.area_expose_cb)
        def motion_notify(ruler, event):
            return ruler.emit("motion_notify_event", event)
        self.area.connect_object("motion_notify_event", motion_notify,
                                 self.hruler)
        self.area.connect_object("motion_notify_event", motion_notify,
                                 self.vruler)
        self.hadj = self.sw.get_hadjustment()
        self.vadj = self.sw.get_vadjustment()
        def val_cb(adj, ruler, horiz):
            if horiz:
                span = self.sw.get_allocation()[3]
            else:
                span = self.sw.get_allocation()[2]
            l,u,p,m = ruler.get_range()
            v = adj.value
            ruler.set_range(v, v+span, p, m)
            while gtk.events_pending():
                gtk.main_iteration()
        self.hadj.connect('value-changed', val_cb, self.hruler, True)
        self.vadj.connect('value-changed', val_cb, self.vruler, False)
        def size_allocate_cb(wid, allocation):
            x, y, w, h = allocation
            l,u,p,m = self.hruler.get_range()
            m = max(m, w)
            self.hruler.set_range(l, l+w, p, m)
            l,u,p,m = self.vruler.get_range()
            m = max(m, h)
            self.vruler.set_range(l, l+h, p, m)
        self.sw.connect('size-allocate', size_allocate_cb)
        self.area.show()
        self.hruler.show()
        self.vruler.show()
        self.sw.show()
        self.table.show()
        window.show()

Es wäre echt total Spitze, wenn es sich vllt jemand ein bisschen Zeit nehmen könnte mir diesen Teil zu erklären:

Code: Alles auswählen

        self.area.set_events(gtk.gdk.POINTER_MOTION_MASK |
                             gtk.gdk.POINTER_MOTION_HINT_MASK )
        self.area.connect("expose-event", self.area_expose_cb)
        def motion_notify(ruler, event):
            return ruler.emit("motion_notify_event", event)
        self.area.connect_object("motion_notify_event", motion_notify,
                                 self.hruler)
        self.area.connect_object("motion_notify_event", motion_notify,
                                 self.vruler)
        self.hadj = self.sw.get_hadjustment()
        self.vadj = self.sw.get_vadjustment()
        def val_cb(adj, ruler, horiz):
            if horiz:
                span = self.sw.get_allocation()[3]
            else:
                span = self.sw.get_allocation()[2]
            l,u,p,m = ruler.get_range()
            v = adj.value
            ruler.set_range(v, v+span, p, m)
            while gtk.events_pending():
                gtk.main_iteration()
        self.hadj.connect('value-changed', val_cb, self.hruler, True)
        self.vadj.connect('value-changed', val_cb, self.vruler, False)
        def size_allocate_cb(wid, allocation):
            x, y, w, h = allocation
            l,u,p,m = self.hruler.get_range()
            m = max(m, w)
            self.hruler.set_range(l, l+w, p, m)
            l,u,p,m = self.vruler.get_range()
            m = max(m, h)
            self.vruler.set_range(l, l+h, p, m)
        self.sw.connect('size-allocate', size_allocate_cb)
Denn dieser Teil ist leider nicht so wirklich toll beschrieben wie ich finde.
Für jemand der nur bis zu diesem Teil mit GTK zu tun hatte, ist er wirklich nicht so einfach zu verstehen.

Vielen Dank schon mal.
Dauerbaustelle
User
Beiträge: 996
Registriert: Mittwoch 9. Januar 2008, 13:48

Donnerstag 1. Januar 2009, 23:39

O________o

Der Code ist grausig. Junger Vadder!

(Sorry dass ich nix konstruktives beitragen konnte^^)
gugugs
User
Beiträge: 113
Registriert: Dienstag 30. Dezember 2008, 12:38

Donnerstag 1. Januar 2009, 23:43

Hm, oke, kennt dann vllt jemand ein besseres Tutorial? Oder eine bessere Möglichkeit, dieses Thema zu lernen?
Dauerbaustelle
User
Beiträge: 996
Registriert: Mittwoch 9. Januar 2008, 13:48

Donnerstag 1. Januar 2009, 23:49

Ja, natürlich: Einfach selbst ausprobieren!

Versuche, irgendwelche lustigen Spiele zu schreiben oder schreibe dir einen Anwendungsstarter für deine meistgenutzten Programme. Oder hack dir mit gtkmozemed nen Browser zusammen.

Oder so was in der Art. Am meisten und schnellsten und besten lernt man (sofern man die Grundlagen beherrscht), indem man selbst ausprobiert, nicht weiterkommt und auf die Nase fliegt.

Ich habe auch mit dem pygtk-Tutorial angefangen, ohne Vorwissen. Ich kann sagen, dass ich python mittlerweile ganz gut beherrsche.

<wisper>Obwohl mit manchmal das Hintergrundwissen fehlt, anwenden kann ichs</wisper>
gugugs
User
Beiträge: 113
Registriert: Dienstag 30. Dezember 2008, 12:38

Freitag 2. Januar 2009, 00:02

Das versuche ich auch, so hab ich mich schon durch PHP gebissen^^

Und jetzt wollte ich ein Programm machen, bei dem man 2 Koordinaten eingibt, und dann eine Linie gezeichnet wird. Das mit dem draw_blub ist mir jetzt nach der vorherigen Erklärung klar. Aber da sind ja dann noch ein paar andere Probleme, z.B.: das mit dem, das wenn sich was ändert, sich das Programm neu zeichnen soll. Und das mit den Ruler hätte ich gern so gehabt, dass da wo die Maus ist, das die Ruler mit der Maus gehen und sich verändern. Jetzt wollte ich mir das Tutorial zur Hilfe nehmen, aber jetzt bin ich wie schon gesagt genau an der blöden Stelle, wo ich diesen Teil ÜBERHAUPT nicht verstehe, und dazu das Beispielsscript auch noch sehr schlecht ist :S
Antworten