Cursor-Position bei einem Entry-Widget

Fragen zu Tkinter.
Benutzeravatar
wuf
User
Beiträge: 1478
Registriert: Sonntag 8. Juni 2003, 09:50

Mittwoch 24. September 2008, 16:54

Hallo Forumfreunde

Gib es eine Möglichkeit die aktuelle Cursor-Position in einem Entry-Widget als Index zurück zu lesen.

Besten Dank für eure Mühe.

Gruss wuf :wink:
Take it easy Mates!
yipyip
User
Beiträge: 418
Registriert: Samstag 12. Juli 2008, 01:18

Mittwoch 24. September 2008, 17:29

Das müsste die Methode

Code: Alles auswählen

my_entry.index(tk.INSERT)
sein, die den aktuellen Index
(da, wo der Cursor blinkt)
zurückliefert.

:wink:
yipyip
Benutzeravatar
wuf
User
Beiträge: 1478
Registriert: Sonntag 8. Juni 2003, 09:50

Mittwoch 24. September 2008, 22:59

Hallo yipyip

Deine Antwort ist genau die Lösung vonach ich drei Stunden erfolglos gesucht und herumexperimentiert habe. Besten Dank für deine hilfreiche Unterstützung! Ich wollte ein Engabe-Widget konstruieren, welches als Eingabe nur Ziffern akzeptiert. Hier meine Lösung die wohl funktioniert aber sicher noch nicht das gelbe vom Ei ist:

Code: Alles auswählen

# Verfasser : wuf
# Skriptname: entry_num_filter_01.py
# Datum     : 24.09.2008

import Tkinter as tk
from string import digits, printable

def entry_key_press(event=None):

    cursor_pos = entry.index('insert')

    if event.keysym in printable:
        if event.keysym in digits:
            return
        else:
            entry.after_idle(remove_char, cursor_pos)

def remove_char(cursor_pos):

    entry.delete(cursor_pos)

root = tk.Tk()
root.geometry('200x100')

entry = tk.Entry(root, width=20, bg='white', bd=1,
    highlightthickness=0)
entry.place(x=20,y=20)
entry.bind('<KeyPress>',entry_key_press)
entry.focus_set()

root.mainloop()
Danke! Gruss wuf :wink:
Take it easy Mates!
Benutzeravatar
wuf
User
Beiträge: 1478
Registriert: Sonntag 8. Juni 2003, 09:50

Donnerstag 25. September 2008, 07:00

Korrektur:

event.keysym muss durch event.char ersetzt werden!

Noch ausstehende Mängel:

a) Umlaute werden noch nicht abgefangen
b) Die 'Ins'-Taste auf meinem Keyboard kopiert etwas aus der Zwischenablage ins Entry-Feld
Take it easy Mates!
yipyip
User
Beiträge: 418
Registriert: Samstag 12. Juli 2008, 01:18

Donnerstag 25. September 2008, 17:11

Habe versucht, die Probleme a) und b) zu elimieren:

Code: Alles auswählen

import Tkinter as tk
import string 

####

class My_entry(object):

  def __init__(self, root):

    self.svar = tk.StringVar()
    self.entry = tk.Entry(root,
                          textvariable=self.svar,
                          width=20, bg='white', bd=1)

    self.entry.bind('<Key>', self.filter_digits)
    self.entry.pack()
    self.entry.focus_set()
    
   
  def filter_digits(self, ev):

    self.s = ''.join([d for d in self.entry.get() if d in string.digits])
    self.svar.set(self.s)

    pos = self.entry.index(tk.INSERT)
    if not ev.keysym in string.digits:
      self.entry.after_idle(lambda i: self.entry.delete(i), pos)
                     
####

root = tk.Tk()
e = My_entry(root)
root.mainloop()

####
Ob's noch gelber geht ?
:K

:wink:
yipyip
Zuletzt geändert von yipyip am Donnerstag 25. September 2008, 18:33, insgesamt 1-mal geändert.
yipyip
User
Beiträge: 418
Registriert: Samstag 12. Juli 2008, 01:18

Donnerstag 25. September 2008, 17:34

Doch, es geht noch gelber. :D

Code: Alles auswählen

import Tkinter as tk
import string 

####

class My_entry(object):

  def __init__(self, root):

    self.svar = tk.StringVar()
    self.entry = tk.Entry(root,
                          textvariable=self.svar,
                          width=20, bg='white', bd=1)

    self.entry.bind('<Key>', self.filter_digits)
    self.entry.pack()
    self.entry.focus_set()
    self.digits_kp = list(string.digits) + ['KP_' + c for c in string.digits]
    
   
  def filter_digits(self, ev):

    self.s = ''.join([d for d in self.entry.get() if d in string.digits])
    self.svar.set(self.s)

    pos = self.entry.index(tk.INSERT)
    if not ev.char in self.digits_kp:
      self.entry.after_idle(lambda i: self.entry.delete(i), pos)
                     
####

root = tk.Tk()
e = My_entry(root)
root.mainloop()

####
Jetzt funktioniert's auch mit dem Nummernblock.

:D
yipyip
Zuletzt geändert von yipyip am Donnerstag 25. September 2008, 18:33, insgesamt 1-mal geändert.
yipyip
User
Beiträge: 418
Registriert: Samstag 12. Juli 2008, 01:18

Donnerstag 25. September 2008, 17:53

Dachte, ich haette es...
aber die 'Ins'-Taste kopiert weiterhin
ins Entry-Feld.
:(
yipyip
Benutzeravatar
wuf
User
Beiträge: 1478
Registriert: Sonntag 8. Juni 2003, 09:50

Donnerstag 25. September 2008, 18:38

Hallo yipyip

Danke, dass du dir noch die Mühe genommen hast mein Problem mit dem Entry-Filter genauer zu untersuchen. Dein Filter scheint absolut dicht zu sein gegen bekannte und unbekannte Tastatureingaben. Das mit der 'Ins'-Taste muss irgendwie auf Tcl-Ebene ablaufen ist vielleich schwierig zu unterbinden.

Jetzt besteht noch ein Problem mit den Steuertasten 'Home', 'End', pfeil-rechts, pfeil-links. Wenn du möchtest könntest du einmal folgendes ausprobieren

a) Gebe einige Ziffern ins Eingabefeld ein z.B. 0123456789
b) Schalte zwischen den 'Home' und 'End' hin und her.
c) Bewege den Cursor mit den Pfeil-Tasten hin und her

Bei diesem Versuch stellte ich auf meinem Notebook fest, dass eingegebene Nummern aus dem Eingabefeld gelöscht werden.

Ich habe mich auch noch weiter mit der Aufgabe beschäftigt. Ich möchte dir meine Variante nicht vorenthalten. Der Code ist noch nicht optimiert. Habe damit noch ein kleines Problem damit. Beim gleichzeitigen aktivieren von zwei Buchstabentasten rutscht ein Buchstabe durch das Filter und gelangt ins Eingabfeld. Funktionier übrigends bei deinem Code problemlos. Hier mein Code natürlich noch nicht auf einer Ebene wie du dich gewöhnt bist zu schreiben. :D

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: UTF-8 -*-

# Verfasser : wuf
# Skriptname: entry_num_filter_02.py
# Datum     : 25.09.2008

# Funktion  : Eingabe nur für Ziffern

import Tkinter as tk
from string import digits, printable, punctuation

def entry_key_press(event=None):

    cursor_pos = entry.index('insert')

    if event.char in printable:
        if event.char in digits:
            #~~ Nur Ziffern
            return
        else:

            entry.after_idle(remove_char, cursor_pos)

    if event.char in "äöüÄÖÜàéèÀÉȧ°ç£":
        #~~ Umlaute und weitere Sonderzeichen
        entry.after_idle(remove_char, cursor_pos)

def remove_char(cursor_pos):

    entry.delete(cursor_pos)

root = tk.Tk()
root.geometry('200x100')

entry = tk.Entry(root, width=20, bg='white', bd=1,
    highlightthickness=0)
entry.place(x=20,y=20)

entry.bind('<KeyPress>',entry_key_press)

entry.focus_set()

root.mainloop()
Danke. Gruss wuf :wink:
Take it easy Mates!
yipyip
User
Beiträge: 418
Registriert: Samstag 12. Juli 2008, 01:18

Donnerstag 25. September 2008, 21:49

Ich hatte nicht berücksichtigt, dass 'Home' und 'End' zwar
ein Event erzeugen, aber kein zu löschendes Zeichen.

So herum funktioniert es bei mir:

Code: Alles auswählen

#!/usr/bin/env python

import Tkinter as tk
import string 

####

class My_entry(object):

  def __init__(self, root):

    self.svar = tk.StringVar()
    self.entry = tk.Entry(root,
                          textvariable=self.svar,
                          width=20, bg='white', bd=1)

    self.entry.bind('<Key>', self.filter_digits)
    self.entry.pack()
    self.entry.focus_set()

   
  def filter_digits(self, ev):

    in_str =  self.entry.get()
    self.s = ''.join([d for d in in_str if d in string.digits])
    self.svar.set(self.s)

    if ev.char in string.digits:
      return

    pos = self.entry.index(tk.INSERT)
    self.entry.after_idle(lambda i: self.entry.delete(i), pos)  
        
                   
####

root = tk.Tk()
e = My_entry(root)
root.mainloop()

####

Das sollte jetzt 'gelb' genug sein. :D

Dein Problem mit den 2 Buchstaben kann ich bei mir nicht
nachvollziehen, bei mir funktioniert's.
(Nur ein 'ß' lässt es noch durch.)

:wink:
yipyip

P.S.
'Home' und 'End' gehen als Leerstring durch, sind daher auch in string.digits .
Zuletzt geändert von yipyip am Freitag 26. September 2008, 00:23, insgesamt 1-mal geändert.
yipyip
User
Beiträge: 418
Registriert: Samstag 12. Juli 2008, 01:18

Donnerstag 25. September 2008, 22:40

...ist mal wieder alles noch komplizierter...

Zahlen eingeben, dann TAB und eine Buchstabentaste
gleichzeitig drücken, danach wieder Zahlen eingeben!
(Bei beiden Programmen)

Aber damit kann ich (man) leben.

:wink:
yipyip
Benutzeravatar
wuf
User
Beiträge: 1478
Registriert: Sonntag 8. Juni 2003, 09:50

Freitag 26. September 2008, 14:59

Hallo yipyip

Danke für dein letztes Code-Snippet. Ich habe es auch wieder näher ausgetestet.

Feststellungen:
a) Test-1: Wie du schon erwähnt hast den Test mit TAB vorhandenen Ziffern markieren und mit einer Buchstabentaste den Text löschen hinterlässt den Buchstaben im Eingabefeld.
b) Test-2: Das gleiche gilt für die folgende Sequenz: HOME (setzt Cursor an den Anfang des im Eingabefeld vorhandenen Textes), SHIFT gedrückt plus END aktivieren (markiert den vorhandenen Text im Eingabefeld), eine Buchstabentaste aktivieren (löscht den markierten Text), zum Schluss steht auch wieder der zum löschen verwendete Buchstabe im Eingabefeld!
c) Test-3: Ziffern 0...9 ins Eingabefeld eintippen. Den Cursor mit der Pfeiltaste vor die Nummer 5 setzen und die DEL-Tatse aktivieren. Diese Aktion entfernt zwei Zeichen ab der Cursorposition!
d) Test-4: Wie du auch schon erwähnt hast hinterlässt das Aktivieren der INSERT-Taste Zeichen die sich momentan in der Zwischenablage befinden im Eingabefeld. Ist eine unschöne Sache. Muss eine Funktion auf Tcl-Ebene sein, die früher für das Einfügen aus der Zwischenablage verwendet wurde, welche für den neuzeitigen Einsatz von Tkinter nicht unterbunden wurde. Dies kann mit CTRL-V ausgeführt werden.
e) Test-5: Wie du sagtest hinterlässt das gleichzeitige betätigen zweier Buchstaben keine Buchstaben im Eingabefeld.

Habe diese Test mit meinem Skript ausgeführt und entsprechende Änderungen vorgenommen um die negativen Symptome zu eliminieren. Dies hatte nichts mehr mit 'strait forward programming' zu tun es ging eher in Richtung 'Teufel-Austreibung'. :lol:

Hier der letzte Stand meines Skriptes:

[Code ausgelagert]

Gruss wuf :wink:
Take it easy Mates!
yipyip
User
Beiträge: 418
Registriert: Samstag 12. Juli 2008, 01:18

Freitag 26. September 2008, 16:55

Danke für den Hinweis auf die Doppel-Löschung,
hab's auch gleich bei mir verbessert.

Zu e)
Um Missverstaendnissen vorzubeugen:
Ich hatte ursprünglich gemeint, dass ich bei
*Deinem* Programm den Doppelbuchstabenfehler nicht
reproduzieren konnte.


Für meinen Geschmack geht das Ganze in die Richtung,
*gegen* die Gui zu programmieren.
(Du hast den Aufwand ja gemerkt ... :wink: )
Vielleicht wäre ja auch z.B. eine Matrix aus Ziffern-Buttons
die Alternative?

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

Freitag 26. September 2008, 23:22

Hier meine (hoffentlich :wink:) letzte Version:

Code: Alles auswählen

#!/usr/bin/env python

import Tkinter as tk
import string 

####

class My_entry(object):

  def __init__(self, root):

    self.svar = tk.StringVar()
    self.entry = tk.Entry(root,
                          textvariable=self.svar,
                          width=20, bg='white', bd=1)

    self.entry.bind('<KeyPress>', self.filter_digits)
    self.entry.pack()
    self.entry.focus_set()

   
  def filter_digits(self, ev):

    in_str =  self.entry.get()
    self.s = ''.join([d for d in in_str if d in string.digits])
    self.svar.set(self.s)

    #print ev.keysym
    #print ev.char

    if ev.keysym in ['Delete']:
      return
    
    if ev.char in string.digits:
      return
  
    pos = self.entry.index(tk.INSERT)
    self.entry.after_idle(lambda i: self.entry.delete(i), pos)  

    #print self.svar.get()    
                   
####

root = tk.Tk()
e = My_entry(root)
root.mainloop()

####
Bei Tab+Buchstabe und nichtleerem Eingabefeld erscheint
zwar der Buchstabe, dieser wird aber nicht übernommen.


Probiere mal mit Deiner letzten Version bei
nichtleerem Eingabefeld:

Ende+Shift(L oder R) gedrückt halten, dann Buchstabentaste (z.B. 'S')

:wink:
yipyip
Benutzeravatar
wuf
User
Beiträge: 1478
Registriert: Sonntag 8. Juni 2003, 09:50

Samstag 27. September 2008, 08:10

Hallo yipyip

Danke für den Tipp. Da ist wirklich noch etwas anzuschauen. :lol:

Ich befürchte es ist immer noch nicht das Ende der Geschichte. Ich habe deine letzte Variante noch ausprobiert. Probier mal die Ziffern 0....9 einzugeben. Dann fahre den Cursor in die Mitte der Eingabe und drücke die ENTER-Taste. Hier wird die Ziffer neben dem Cursor gelöscht.

Mein Setup hier ist: Python2.5, SuSE10.0, Notebook TOSHIBA-Satellite
(eventuell kann die Harsware auch noch eine Rolle spielen, was ich nicht hoffe)

OK 'yipyip' ich werden noch weiterforschen. Bei weiteren Erfolgen werde ich dich informieren.

Gruss wuf :wink:
Take it easy Mates!
Benutzeravatar
kaytec
User
Beiträge: 544
Registriert: Dienstag 13. Februar 2007, 21:57

Samstag 27. September 2008, 08:25

Hallo wuf !

Evt. hilft dir das weiter oder es ist einfach nur dein Problem nicht verstanden.

http://paste.pocoo.org/show/86337/

gruss frank
Antworten