Taschen-Rechner

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
8800gtx
User
Beiträge: 1
Registriert: Montag 11. Oktober 2010, 20:56

Hallo,

Ich bin erst ein Anfänger in der Sache Python und der Programmierung, ich habe folgendes ein Programmcode, einen Taschenrechner

Code: Alles auswählen

from Tkinter import *

class Rechner(Tk):                           
  def __init__(self):
    Tk.__init__(self)                               
    self.title('Taschenrechner')
    self.ende=0 
                                        
    self.anzeige=Anzeige(self)
    self.anzeige.grid(column=0,row=0,sticky=E+W,
                      columnspan=6, pady=5)         
    raster=[(0,1,'7'),(1,1,'8'),(2,1,'9'),(3,1,'/'),
            (0,2,'4'),(1,2,'5'),(2,2,'6'),(3,2,'*'),
            (0,3,'1'),(1,3,'2'),(2,3,'3'),(3,3,'-'),
            (0,4,'0'),(1,4,'%'),(3,4,'+')]
    for (i,j,t) in raster:  
       Taste(self,t).grid(column=i,row=j)     
    Clear(self).grid(column=5,row=1)
    Gleich(self).grid(column=5,row=2)
    self.mainloop()

class Taste(Button):
  def __init__(self, fenster,t):
    Button.__init__(self,fenster,
                    bg='black',
                    fg='green',
                    width=4,
                    height=2,
                    text=t,
                    font=('Arial',14,'bold'),
                    command=self.eintragen)
    self.zeichen=t
    self.fenster=fenster

  def eintragen(self):
    d=self.fenster.anzeige
    if self.fenster.ende:                           
        d.delete(0,len(d.get()))
        self.fenster.ende=0
    d.eintragen(self.zeichen)

class Clear(Button):
  def __init__(self, fenster):
    Button.__init__(self,
                    fenster,
                    text='C',
                    bg='black',
                    fg='red',
                    width=4,
                    height=2,
                    font=('Arial',14,'bold'),
                    command=self.loeschen)
    self.anzeige=fenster.anzeige

  def loeschen(self):
    self.anzeige.loeschen()

class Gleich(Button):
  def __init__(self, fenster):
    Button.__init__(self,
                    fenster,
                    text='=',
                    bg='black',
                    fg='yellow',
                    width=4,
                    height=2,
                    font=('Arial',14,'bold'),
                    command=self.rechnen  
                    
)
    self.fenster=fenster

  def rechnen(self):
    ergebnis=eval(self.fenster.anzeige.get())       
    ende=len(self.fenster.anzeige.get())
    self.fenster.anzeige.insert(ende, '='+str(ergebnis))
    self.fenster.ende=1

class Anzeige(Entry):
  def __init__(self,fenster):
    Entry.__init__(self, fenster,width=20,font=('Courier New',16))

  def eintragen (self,zeichen):
    self.insert(len(self.get()),zeichen)

  def loeschen(self):

    self.delete(0,len(self.get()))                 

app=Rechner()    



 


Jetzt ich meine Frage das Programm läuft ohne Probleme jetzt will in das Programm einen Code hinzufügen wenn ich das Ergebniss ausgeben will nicht auf = Zeichen drücken muss sondern die Enter Taste drücke wie schreibe ich den Code ?

Danke

lg 8800gtx
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

8800gtx hat geschrieben: Jetzt ich meine Frage das Programm läuft ohne Probleme jetzt will in das Programm einen Code hinzufügen wenn ich das Ergebniss ausgeben will nicht auf = Zeichen drücken muss sondern die Enter Taste drücke wie schreibe ich den Code ?
Hm... als Anfänger sollte man sich nicht unbedingt gleich mit GUI-Programmierung auseinander setzen. Wieso, sieht man schön an Deinem Code.

Du solltest lieber noch einmal das Tutorial durchackern. Zudem folgende Tipps:

- PEP8 beachten
- GUI und Logik trennen (zugegeben ist die Logik hier sehr simpel ;-) )
- benutze kein eval!
- Studiere mal die Doku zu Tk intensiver. Ich wette man kann viele Dinge aus den Objekten wieder herausziehen und muss sich dafür nicht eigene Attribute anlegen, wie z.B. hier:

Code: Alles auswählen

class Gleich(Button):
  def __init__(self, fenster):
    # ...
    self.fenster=fenster
- Muss man bei Tk wirklich eine eigene Klasse erstellen nur für das "Styling"? Vor allem hätte da doch ein Button gereicht, dem man nur jeweils ggf. eine spezielle Callback-Funktion übergibt.

Wenn Du jedoch schon so weit gekommen bist mit Deinem Projekt, dann wirst Du ja auch in der Doku zu Tk finden, wie man Tastaturabfragen realisieren kann?

Noch kurz etwas zu den Formalien: Achte doch bitte mehr auf Rechtschreibung und Zeichensetzung, sowie Groß- und Kleinschreibung. Dein Beitrag liest sich extrem schwer und zeugt nicht davon, dass Du Dir Mühe gegeben hast damit.

Für Python-Code gibt es übrigens spezielle Code-Tags

Code: Alles auswählen

 ... [ /python] (ohne die Leerzeichen).
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Benutzeravatar
__blackjack__
User
Beiträge: 13115
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@8800gtx: Weil das hier kürzlich von einem anderen Beitrag aus verlinkt wurde noch eine Antwort.

Spätestens jetzt sollte man Python 3 statt Python 2 verwenden.

Sternchen-Importe sind Böse™. Da holt man sich gerade bei `tkinter` fast 200 Namen ins Modul von denen nur ein kleiner Bruchteil verwendet wird. Auch Namen die gar nicht in `tkinter` definiert werden, sondern ihrerseits von woanders importiert werden. Das macht Programme unnötig unübersichtlicher und fehleranfälliger und es besteht die Gefahr von Namenskollisionen.

Auf Modulebene sollte nur Code stehen der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst.

Die `mainloop()`-Methode sollte nicht in der `__init__()` aufgerufen werden. Diese Methode ist dazu da ein verwendbares Objekt zu initialisieren, nicht das gesamte Programm ablaufen zu lassen.

Ich schliesse mich Hyperion an. Da sind zu viele unnötige Klassen. Die kann man beseitigen und einfach direkt die Widgets verwenden von denen abgeleitet wird. Die Funtkionalität kann man über Callbacks und gegebenfalls `functools.partial()` umsetzen.

Das `ende`-Attribut nimmt nur die Werte 0 und 1 an und wird ausschliesslich als ``if``-Bedingung ausgewertet: Das ist also keine Zahl sondern ein Wahrheitswert und dafür gibt es die Werte `True` und `False`. Man sollte da keine Zahlen für missbrauchen.

Der Name `ende` ist auch nicht besonders gut. Man muss erst schauen wofür das verwendet wird um zu verstehen was es bedeutet.

Die `len()`-Aufrufe auf den Inhalt der Anzeige sind alle überflüssig weil man dort jeweils die Konstante `tkinter.END` verwenden kann.

Bei `raster` sind die Zahlen in den Tupeln redundant. Wenn man die Beschriftungen der Tasten als zweidimensionale Liste repräsenntiert, dann sind die Zahlen in den Tupeln im Grunde nur der jeweilige Index der Zeile beziehungsweise Spalte. Und die kann man mit `enumerate()` aufzählen, statt sie per Hand alle in den Quelltext zu schreiben.

Zwischenstand (ungetestet):

Code: Alles auswählen

#!/usr/bin/env python3
import tkinter as tk
from functools import partial


class Rechner(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
        self.title("Taschenrechner")
        self.anzeige_muss_geleert_werden = False

        self.anzeige = tk.Entry(self, font=("Courier New", 16))
        self.anzeige.grid(column=0, row=0, sticky=tk.EW, columnspan=6, pady=5)

        options = {
            "background": "black",
            "font": ("Arial", 14, "bold"),
            "height": 2,
            "width": 4,
        }
        raster = [
            ["7", "8", "9", "/"],
            ["4", "5", "6", "*"],
            ["1", "2", "3", "-"],
            ["0", "%", None, "+"],
        ]
        for i, row in enumerate(raster, 1):
            for j, text in enumerate(row):
                if text is not None:
                    tk.Button(
                        self,
                        text=text,
                        foreground="green",
                        command=partial(self.eintragen, text),
                        **options,
                    ).grid(row=i, column=j)

        tk.Button(
            self,
            text="C",
            foreground="red",
            command=lambda: self.anzeige.delete(0, tk.END),
            **options,
        ).grid(column=5, row=1)

        tk.Button(
            self,
            text="=",
            foreground="yellow",
            command=self.rechnen,
            **options,
        ).grid(column=5, row=2)

    def eintragen(self, text):
        if self.anzeige_muss_geleert_werden:
            self.anzeige.delete(0, tk.END)
            self.anzeige_muss_geleert_werden = False
        self.anzeige.insert(tk.END, text)

    def rechnen(self):
        #
        # FIXME `eval()` is dangerous here.  The user can enter any valid Python
        # expression, including something like ``__import__("os").system("rm -rf
        # ~")``.
        #
        # FIXME Handle invalid input and errors while evaluating like division
        # by zero.
        #
        self.anzeige.insert(tk.END, f"={eval(self.anzeige.get())}")
        self.anzeige_muss_geleert_werden = True


def main():
    app = Rechner()
    app.mainloop()


if __name__ == "__main__":
    main()
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Antworten