Programm - Quiz

Fragen zu Tkinter.
Antworten
Totz
User
Beiträge: 6
Registriert: Mittwoch 13. Januar 2010, 00:06

Hi!
Bin neu hier.
Bin immer mal ein wenig mit Python in Kontakt, bedingt durch das arbeiten mit Blender. Nun habe ich mal angefangen mein erstes Programm mit UI zu schreiben...
Habe leider noch einige Probleme:

- wie bekomme ich es hin das immer nur ein tkinter Fenster auf bleibt?
- Wie kriege ich die Meldung 'Keine Fragen mehr vorhanden' noch in den tkinter bereich? Also das es in dem Fenster angezeigt wird?
- Wie stelle ich ein, dass die Button a,b und c neben einander angezeigt werden?
- Was kann man an der effektivität ändern? bzw. vom Aufbau/Struktur her?

Danke schon mal im Vorraus.

Gruß Totz

http://www.pasteall.org/10261/python

Code: Alles auswählen

import random
from tkinter import *

Fragen = ['5 + 6 = ?\na=11 b=4 c=18 ','1 + 2 = ?\na=-1 b=32 c=3 ','4 + 7 = ?\na=7 b=11 c=20 ']
Ergebnis = ['a','c','b']

Eingabe = 0

def Quiz():

  AnzahlDerFragen = len(Fragen)

  root = Tk()

  if AnzahlDerFragen > 0:

    def Input(x):
      global Eingabe
      Eingabe = x

      Zufall1 = Zufall + 1
      Löschen = Zufall
    
      if Eingabe == Ergebnis[Zufall]:
        textfenster.insert('2.end','Die Antwort ist richtig!')
        #print('Die Antwort ist richtig!')
        Fragen[Löschen:Zufall1] = []
        Ergebnis[Löschen:Zufall1] = []
        return Quiz()

      else:
        textfenster.insert('2.end','Bitte versuchen sie es nocheinmal!')
        #print('Bitte versuchen sie es nocheinmal!')
        return Quiz()
      
    
    Zufall = random.randrange(0,AnzahlDerFragen)
    Ausgabe = Fragen[Zufall]

    lab = Label(root,text=Ausgabe)
    lab.pack()
    textfenster = Text(root,height=2,width=50)
    textfenster.pack()
    abut = Button(root,text='a',command = lambda x = 'a': Input(x))
    abut.pack()
    bbut = Button(root,text='b',command = lambda x ='b': Input(x))
    bbut.pack()
    cbut = Button(root,text='c',command = lambda x = 'c': Input(x))
    cbut.pack()
    root.mainloop()

  else:
    print('Keine Fragen mehr vorhanden!')
    exit
  

Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Vielleicht hast du dir für den allerersten Anfang etwas zu viel auf einmal vorgenommen. Ein paar Gedanken:

Es gibt einige Konventionen für die Erstellung von Python-Code, die man möglichst einhalten sollte, weil dadurch Quelltext (nicht nur für andere) leichter lesbar ist (Stichwort wäre "PEP8"). Dazu gehört u.a. dass Bezeichner, sofern es nicht Klassenbezeichner sind, klein geschrieben werden. Außerdem sind (für meinen Geschmack) ein paar zu viele Leerzeilen drin.

Dass es "global" gibt, vergisst du am besten wieder. Das hat häufig unerwünschte (und unbedachte) Seiteneffekte zur Folge und macht Code schlecht wartbar. Grundsatz: "Werte betreten eine Funktion als Parameter und verlassen sie als Rückgabewert."

Du solltest die Programmlogik und die GUI deutlich trennen. Ein möglicher Weg könnte sein, das Quiz zunächst ganz ohne GUI zu entwerfen - das kann man schließlich auch gut über die Konsole spielen. Dabei solltest du dich dann zunächst darauf konzentrieren.

Soll das Quiz in seiner endgültigen Form auch nur Grundrechenaufgaben anbieten, dann solltest du diese nicht vorproduzieren, sondern vom Programm während der Laufzeit produzieren lassen. Sollen auch andere Fragen gestellt werden, die sich nicht vom Programm erzeugen lassen, dann solltest du die Fragen und Antworten in einer Datei ablegen und vom Programm einlesen lassen.

Anschließend oder parallel dazu könntest du dann einige Einstiegsübungen zu Tkinter machen. Denn so wie dein Code aussieht, hast du Grundlagen davon noch nicht verstanden. Deine Fragen wirst du dir dann selbst beantworten können.
Totz
User
Beiträge: 6
Registriert: Mittwoch 13. Januar 2010, 00:06

Gut danke das du mich wieder auf den Boden der Tatsachen gehohlt hast ! ;) Ist vielleicht wirklich fürn Anfang zu viel. Ich habe schon einführungs Tuts von TKinter durchgearbeitet. Ich weis wie man Buttons, Labels... einstellt nur halt ebend nicht genau wie ich es mit nem Programm verbinde...

Habe ich das mit den klein buchstaben jetzt richtig verstanden?
Ist es von der Logik her richtig aufgebaut?

Ohne TKinter

Code: Alles auswählen

import random

Fragen = ['5 + 6 = ?\na=11 b=4 c=18 ','1 + 2 = ?\na=-1 b=32 c=3 ','4 + 7 = ?\na=7 b=11 c=20 ']
Ergebnis = ['a','c','b']


def quiz():

  AnzahlDerFragen = len(Fragen)

  if AnzahlDerFragen > 0:

    Zufall = random.randrange(0,AnzahlDerFragen)
    Ausgabe = Fragen[Zufall]

    Zufall1 = Zufall + 1
    Löschen = Zufall

    print (Ausgabe)
    Eingabe = input()
    
    if Eingabe == Ergebnis[Zufall]:
      
      print('Die Antwort ist richtig!')
      Fragen[Löschen:Zufall1] = []
      Ergebnis[Löschen:Zufall1] = []
      return Quiz()

    else:
        
        print('Bitte versuchen sie es nocheinmal!')
        return Quiz()
    
  else:
    print('Keine Fragen mehr vorhanden!')
    exit
  

BlackJack

@Totz: Falls Du mit "Kleinbuchstaben" die Namen meinst, dann sind da noch zu viele Grossbuchstaben. Insbesondere rufst Du an zwei Stellen `Quiz()` auf, was es nicht gibt.

Diesen rekursiven Aufruf solltest Du da sowieso nicht machen. Funktionsaufrufe sind nicht für Sprünge gedacht, sondern um sinnvoll Funktionen aufzurufen und danach auch *zurückzukehren*. Das machst Du hier nur zufällig -- weil Du `exit` nur hingeschrieben hast, aber nicht *aufrufst*. Da fehlen die Klammern.

Ansonsten sieht's ein wenig umständlich aus. Fragen und Antworten sollte man nicht in getrennten Datenstrukturen halten, die gehören ja schliesslich zusammen. *Eine* Liste mit Tupeln aus Frage und Antwort wäre zum Beispiel ein Ansatz. Dann könnte man die ganze Liste auch einfach mit der entsprechenden Funktion aus `random` mischen und mit einer ``for``-Schleife die Fragen abarbeiten.
Benutzeravatar
gkuhl
User
Beiträge: 600
Registriert: Dienstag 25. November 2008, 18:03
Wohnort: Hong Kong

Hier mal ein kleines Beispiel wie es aussehen könnte:

Code: Alles auswählen

aufgaben = [ ('1 + 1 = ?', 2), 
             ('1 + 2 = ?', 3),
             ('1 + 3 = ?', 4)
           ]
           
def quiz():
    for frage, antwort in aufgaben:
        print(frage)
        while True:
            versuch = int(input())
            if versuch == antwort:
                print('Richtig!')
                break
            else:
                print('Falsch!')
Grüße
Gerrit

Edit: Nach Hinweis von Totz ``int()`` in Zeile 10 ergänzt.
Zuletzt geändert von gkuhl am Donnerstag 14. Januar 2010, 00:01, insgesamt 1-mal geändert.
Totz
User
Beiträge: 6
Registriert: Mittwoch 13. Januar 2010, 00:06

Danke für die Antworten und Anregungen!
@gkuhl müsste man nicht noch die input Eingabe in eine integer umwandeln? Danke für das Code Beispiel!

Um nochmal auf TKinter zurück zukommen, wie geht man so etwas an? Muss einem von Anfang an klar sein das man ein UI haben möchte und darauf hin programmieren oder kann man das auch gut nach dem coden des "Main Programs"drauf setzten ? Sollte bzw. kann man UI und "Main Program" von einander trennen also komplett unabhänig voneinander machen?

Danke schon mal im Vorraus!!

Gruß Totz
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

In dem Beispiel sollte man noch zu `int`s konvertieren, aber man kann auch einfach die Antworten anpassen.

Ja, man kann Logik und GUI so trennen, dass sie komplett unabhaengig arbeiten, d.h. du kannst die GUI austauschen.
Gaengig ist MVC-Programmierung http://de.wikipedia.org/wiki/Model_View_Controller
Benutzeravatar
gkuhl
User
Beiträge: 600
Registriert: Dienstag 25. November 2008, 18:03
Wohnort: Hong Kong

Totz hat geschrieben:@gkuhl müsste man nicht noch die input Eingabe in eine integer umwandeln?
Okay, das passiert, wenn man für Python 3.x schreibt und es mit Python 2.6 testet. Ich hab's oben mal korrigiert. :?
Benutzeravatar
/me
User
Beiträge: 3561
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

Totz hat geschrieben:Um nochmal auf TKinter zurück zukommen, wie geht man so etwas an? Muss einem von Anfang an klar sein das man ein UI haben möchte und darauf hin programmieren oder kann man das auch gut nach dem coden des "Main Programs"drauf setzten ? Sollte bzw. kann man UI und "Main Program" von einander trennen also komplett unabhänig voneinander machen?
Ich schreibe so etwas immer völlig getrennt, wie cofi es schon als MVC erläutert hat. Das führt dann auch dazu, dass ich im Endeffekt die gleiche Software ohne größeren Aufwand von der Shell, mit einem grafischen Client oder als Webanwendung laufen lassen kann. Nur die Logik für die View muss neu geschrieben werden, der Rest bleibt gleich.

[Sicherheitshalber: Nein, ich schreibe in Python keine Egoshooter die ich dann auf der Konsole in ASCII-Grafik spiele.]
Totz
User
Beiträge: 6
Registriert: Mittwoch 13. Januar 2010, 00:06

Und wie setzte ich das jetzt in Python um? Also wenn wir für das Programm von gkuhl ein UI mit dem MVC Model schreiben möchten. Wie geht man dann da vor? Kann man das auch mit TKinter realisieren?

Gruß
Benutzeravatar
mkesper
User
Beiträge: 919
Registriert: Montag 20. November 2006, 15:48
Wohnort: formerly known as mkallas
Kontaktdaten:

Totz hat geschrieben:Also wenn wir für das Programm von gkuhl ein UI mit dem MVC Model schreiben möchten. Wie geht man dann da vor? Kann man das auch mit TKinter realisieren?
Du entwickelst nicht die GUI nach dem MVC Modell, sondern deine komplette Anwendung. Mit welchem GUI-Toolkit du das umsetzt hängt von deinen Vorlieben ab. Tkinter wird von vielen als nicht mehr zeitgemäß angesehen, was das Aussehen angeht. Dafür soll es relativ einfach einfach zu programmieren sein (jedoch fehlen hier alle möglichen Widgets, die moderne Toolkits "einfach so" mitbringen). Alternativen sind hauptsächlich wxWidgets, GTK und Qt4.
Totz
User
Beiträge: 6
Registriert: Mittwoch 13. Januar 2010, 00:06

Gut, also ist TKinter vielleicht nicht das Best was ich zuerst lernen sollte. Davon aber mal abgesehen wie würde man denn mit TKinter nun an dieses Problem herangehen? Würde mich über ein Code Schnipsel freuen, um einfach mal einen Eindruck zu bekommen. Danke schonmal.

Gruß Totz
yipyip
User
Beiträge: 418
Registriert: Samstag 12. Juli 2008, 01:18

@Totz
Zunaechst brauchst Du etwas Feeling fuer objektorientierte Programmierung. Dann schau Dir mal meine Beispiele in
http://www.python-forum.de/post-113896.html#113896
und
http://www.python-forum.de/post-146380.html#146380
an.

:wink:
yipyip
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Totz hat geschrieben:Würde mich über ein Code Schnipsel freuen, um einfach mal einen Eindruck zu bekommen.
Ich empfehle "Thinking in Tkinter".
BlackJack

@Totz: Ich würde als erstes die Programmlogik, also den Teil ohne GUI, so schreiben, dass man ihn von aussen "schrittweise" benutzen kann. Also so, dass dieser Teil keine irgendwie geartete "Hauptschleife" enthält, die den Programmfortgang antreibt. GUI-Toolkits arbeiten ja in der Regel ereignisbasiert und stellen die Hauptschleife eines Programms dar. Der eigene Code, der in so ein Rahmenwerk eingebunden wird, läuft da nicht ständig sondern Funktionen werden bei bestimmten Ereignissen, wie zum Beispiel einem klick auf eine Schaltfläche, aufgerufen und sollten dann kurz irgendetwas machen und dann die Kontrolle wieder der GUI überlassen.

Das komplette MVC-Muster ist hier IMHO übertrieben. In einer Menge Fällen ist es das IMHO. Sehr oft kann man den Controller und den View in einer Klasse modellieren.

Tkinter ist für die Quiz-Aufgabe IMHO ausreichend. Da werden keine Widgets gebraucht, die Tkinter nicht zur Verfügung stellt, und Du sparst Dir erst einmal die zusätzliche Einarbeitung in ein anderes GUI-Toolkit.

Ein Ansatz: http://paste.pocoo.org/show/165976/
Totz
User
Beiträge: 6
Registriert: Mittwoch 13. Januar 2010, 00:06

Danke! Ich werde mich wohl noch mehr einlesen und versuchen so zu denken wie ihr das alle tut :). EIne frage warum denn immer dieses self?
BlackJack

@Totz: `self` ist halt der Name der per Konvention verwendet wird. Die Frage zeigt, dass Du objektorientierte Programmierung noch nicht verstanden hast. Da sollte Du erst einmal ansetzen, bevor es an die GUI geht.
Antworten