commit
c86bab397e
|
@ -0,0 +1,90 @@
|
||||||
|
import sys
|
||||||
|
import re
|
||||||
|
QT = True
|
||||||
|
if QT:
|
||||||
|
import PySimpleGUIQt as sg
|
||||||
|
else:
|
||||||
|
import PySimpleGUI as sg
|
||||||
|
|
||||||
|
def autocomplete_popup_show(text_list ):
|
||||||
|
autocomplete_popup_layout = [[sg.Listbox(values=text_list,
|
||||||
|
size=(100,20*len(text_list)) if QT else (15, len(text_list)),
|
||||||
|
change_submits=True,
|
||||||
|
bind_return_key=True,
|
||||||
|
auto_size_text=True,
|
||||||
|
key='_FLOATING_LISTBOX_', enable_events=True)]]
|
||||||
|
|
||||||
|
autocomplete_popup = sg.Window("Borderless Window",
|
||||||
|
default_element_size=(12, 1),
|
||||||
|
auto_size_text=False,
|
||||||
|
auto_size_buttons=False,
|
||||||
|
no_titlebar=True,
|
||||||
|
grab_anywhere=True,
|
||||||
|
return_keyboard_events=True,
|
||||||
|
keep_on_top=True,
|
||||||
|
background_color='black',
|
||||||
|
location=(1320,622),
|
||||||
|
default_button_element_size=(12, 1))
|
||||||
|
|
||||||
|
window = autocomplete_popup.Layout(autocomplete_popup_layout).Finalize()
|
||||||
|
return window
|
||||||
|
|
||||||
|
|
||||||
|
def predict_text(input, lista):
|
||||||
|
pattern = re.compile('.*' + input + '.*')
|
||||||
|
return [w for w in lista if re.match(pattern, w)]
|
||||||
|
|
||||||
|
choices = ['ABC' + str(i) for i in range(30)] # dummy data
|
||||||
|
|
||||||
|
layout = [ [sg.Text('Your typed chars appear here:')],
|
||||||
|
[sg.In(key='_INPUT_', size=(10,1), do_not_clear=True)],
|
||||||
|
[sg.Button('Show'), sg.Button('Exit')],]
|
||||||
|
|
||||||
|
window = sg.Window('Window Title', return_keyboard_events=True).Layout(layout)
|
||||||
|
|
||||||
|
sel_item = -1
|
||||||
|
skip_event = False
|
||||||
|
while True: # Event Loop
|
||||||
|
event, values = window.Read(timeout=500)
|
||||||
|
if event is None or event == 'Exit':
|
||||||
|
break
|
||||||
|
if event != sg.TIMEOUT_KEY:
|
||||||
|
# print(f'ev1 {event}')
|
||||||
|
in_val = values['_INPUT_']
|
||||||
|
prediction_list = predict_text(str(in_val), choices)
|
||||||
|
if prediction_list:
|
||||||
|
try:
|
||||||
|
fwindow.Close()
|
||||||
|
except: pass
|
||||||
|
fwindow = autocomplete_popup_show(prediction_list)
|
||||||
|
list_elem = fwindow.Element('_FLOATING_LISTBOX_')
|
||||||
|
if event == '_COMBO_':
|
||||||
|
sg.Popup('Chose', values['_COMBO_'])
|
||||||
|
if event.startswith('Down') or event.startswith('special 16777237'):
|
||||||
|
sel_item = sel_item + (sel_item<len(prediction_list))
|
||||||
|
list_elem.Update(set_to_index=sel_item)
|
||||||
|
skip_event = True
|
||||||
|
elif event.startswith('Up') or event.startswith('special 16777235'):
|
||||||
|
sel_item = sel_item - (sel_item>0)
|
||||||
|
list_elem.Update(set_to_index=sel_item)
|
||||||
|
skip_event = True
|
||||||
|
if event == '\r' or event.startswith('special 16777220'):
|
||||||
|
chosen = vals2['_FLOATING_LISTBOX_']
|
||||||
|
window.Element('_INPUT_').Update(vals2['_FLOATING_LISTBOX_'][0], select=True)
|
||||||
|
fwindow.Close()
|
||||||
|
sel_item = -1
|
||||||
|
if event.startswith('Escape') or event.startswith('special 16777216'):
|
||||||
|
window.Element('_INPUT_').Update('')
|
||||||
|
|
||||||
|
try:
|
||||||
|
ev2, vals2 = fwindow.Read(timeout=10)
|
||||||
|
if ev2 == '_FLOATING_LISTBOX_' and skip_event and QT:
|
||||||
|
skip_event = False
|
||||||
|
elif ev2 != sg.TIMEOUT_KEY and ev2 is not None:
|
||||||
|
# print(f'ev2 {ev2}')
|
||||||
|
fwindow.Close()
|
||||||
|
window.Element('_INPUT_').Update(vals2['_FLOATING_LISTBOX_'][0], select=True)
|
||||||
|
sel_item = -1
|
||||||
|
fwindow = None
|
||||||
|
except: pass
|
||||||
|
window.Close()
|
|
@ -506,7 +506,7 @@ class InputText(Element):
|
||||||
super().__init__(ELEM_TYPE_INPUT_TEXT, size=size, background_color=bg, text_color=fg, key=key, pad=pad,
|
super().__init__(ELEM_TYPE_INPUT_TEXT, size=size, background_color=bg, text_color=fg, key=key, pad=pad,
|
||||||
font=font, tooltip=tooltip)
|
font=font, tooltip=tooltip)
|
||||||
|
|
||||||
def Update(self, value=None, disabled=None):
|
def Update(self, value=None, disabled=None, select=None):
|
||||||
if disabled is True:
|
if disabled is True:
|
||||||
self.TKEntry['state'] = 'disabled'
|
self.TKEntry['state'] = 'disabled'
|
||||||
elif disabled is False:
|
elif disabled is False:
|
||||||
|
@ -517,6 +517,9 @@ class InputText(Element):
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
self.DefaultText = value
|
self.DefaultText = value
|
||||||
|
if select:
|
||||||
|
self.TKEntry.select_range(0, 'end')
|
||||||
|
|
||||||
|
|
||||||
def Get(self):
|
def Get(self):
|
||||||
try:
|
try:
|
||||||
|
@ -2974,6 +2977,7 @@ class Window:
|
||||||
self.DisableClose = disable_close
|
self.DisableClose = disable_close
|
||||||
self._Hidden = False
|
self._Hidden = False
|
||||||
self._Size = size
|
self._Size = size
|
||||||
|
self.XFound = False
|
||||||
|
|
||||||
# ------------------------- Add ONE Row to Form ------------------------- #
|
# ------------------------- Add ONE Row to Form ------------------------- #
|
||||||
def AddRow(self, *args):
|
def AddRow(self, *args):
|
||||||
|
@ -3132,7 +3136,7 @@ class Window:
|
||||||
# print("** REALTIME PROBLEM FOUND **", results)
|
# print("** REALTIME PROBLEM FOUND **", results)
|
||||||
|
|
||||||
if self.RootNeedsDestroying:
|
if self.RootNeedsDestroying:
|
||||||
# print('*** DESTROYING really late***')
|
print('*** DESTROYING really late***')
|
||||||
self.TKroot.destroy()
|
self.TKroot.destroy()
|
||||||
# _my_windows.Decrement()
|
# _my_windows.Decrement()
|
||||||
self.LastButtonClicked = None
|
self.LastButtonClicked = None
|
||||||
|
@ -3173,6 +3177,12 @@ class Window:
|
||||||
self.LastButtonClicked = None
|
self.LastButtonClicked = None
|
||||||
return results
|
return results
|
||||||
else:
|
else:
|
||||||
|
if not self.XFound and self.Timeout != 0 and self.Timeout is not None and self.ReturnValues[
|
||||||
|
0] is None: # Special Qt case because returning for no reason so fake timeout
|
||||||
|
self.ReturnValues = self.TimeoutKey, self.ReturnValues[1] # fake a timeout
|
||||||
|
elif not self.XFound and self.ReturnValues[0] is None: # TODO HIGHLY EXPERIMENTAL... added due to tray icon interaction
|
||||||
|
# print("*** Faking timeout ***")
|
||||||
|
self.ReturnValues = self.TimeoutKey, self.ReturnValues[1] # fake a timeout
|
||||||
return self.ReturnValues
|
return self.ReturnValues
|
||||||
|
|
||||||
def ReadNonBlocking(self):
|
def ReadNonBlocking(self):
|
||||||
|
@ -3353,6 +3363,7 @@ class Window:
|
||||||
# print('Got closing callback', self.DisableClose)
|
# print('Got closing callback', self.DisableClose)
|
||||||
if self.DisableClose:
|
if self.DisableClose:
|
||||||
return
|
return
|
||||||
|
self.XFound = True
|
||||||
if self.CurrentlyRunningMainloop: # quit if this is the current mainloop, otherwise don't quit!
|
if self.CurrentlyRunningMainloop: # quit if this is the current mainloop, otherwise don't quit!
|
||||||
self.TKroot.quit() # kick the users out of the mainloop
|
self.TKroot.quit() # kick the users out of the mainloop
|
||||||
self.TKroot.destroy() # kick the users out of the mainloop
|
self.TKroot.destroy() # kick the users out of the mainloop
|
||||||
|
|
|
@ -539,7 +539,7 @@ class InputText(Element):
|
||||||
self.ReturnKeyHandler(None)
|
self.ReturnKeyHandler(None)
|
||||||
return
|
return
|
||||||
|
|
||||||
def Update(self, value=None, disabled=None):
|
def Update(self, value=None, disabled=None, select=None):
|
||||||
if disabled is True:
|
if disabled is True:
|
||||||
self.QT_QLineEdit.setDisabled(True)
|
self.QT_QLineEdit.setDisabled(True)
|
||||||
elif disabled is False:
|
elif disabled is False:
|
||||||
|
@ -547,6 +547,8 @@ class InputText(Element):
|
||||||
if value is not None:
|
if value is not None:
|
||||||
self.QT_QLineEdit.setText(str(value))
|
self.QT_QLineEdit.setText(str(value))
|
||||||
self.DefaultText = value
|
self.DefaultText = value
|
||||||
|
if select:
|
||||||
|
self.QT_QLineEdit.setSelection(0,QtGui.QTextCursor.End )
|
||||||
|
|
||||||
def Get(self):
|
def Get(self):
|
||||||
return self.QT_QLineEdit.text()
|
return self.QT_QLineEdit.text()
|
||||||
|
@ -571,7 +573,7 @@ Input = InputText
|
||||||
class Combo(Element):
|
class Combo(Element):
|
||||||
def __init__(self, values, default_value=None, size=(None, None), auto_size_text=None, background_color=None,
|
def __init__(self, values, default_value=None, size=(None, None), auto_size_text=None, background_color=None,
|
||||||
text_color=None, change_submits=False, enable_events=False, disabled=False, key=None, pad=None, tooltip=None,
|
text_color=None, change_submits=False, enable_events=False, disabled=False, key=None, pad=None, tooltip=None,
|
||||||
readonly=False, visible_items=10, font=None):
|
readonly=False, visible_items=10, font=None, auto_complete=True):
|
||||||
'''
|
'''
|
||||||
Input Combo Box Element (also called Dropdown box)
|
Input Combo Box Element (also called Dropdown box)
|
||||||
:param values:
|
:param values:
|
||||||
|
@ -589,6 +591,7 @@ class Combo(Element):
|
||||||
bg = background_color if background_color else DEFAULT_INPUT_ELEMENTS_COLOR
|
bg = background_color if background_color else DEFAULT_INPUT_ELEMENTS_COLOR
|
||||||
fg = text_color if text_color is not None else DEFAULT_INPUT_TEXT_COLOR
|
fg = text_color if text_color is not None else DEFAULT_INPUT_TEXT_COLOR
|
||||||
self.VisibleItems = visible_items
|
self.VisibleItems = visible_items
|
||||||
|
self.AutoComplete = auto_complete
|
||||||
|
|
||||||
super().__init__(ELEM_TYPE_INPUT_COMBO, size=size, auto_size_text=auto_size_text, background_color=bg,
|
super().__init__(ELEM_TYPE_INPUT_COMBO, size=size, auto_size_text=auto_size_text, background_color=bg,
|
||||||
text_color=fg, key=key, pad=pad, tooltip=tooltip, font=font or DEFAULT_FONT)
|
text_color=fg, key=key, pad=pad, tooltip=tooltip, font=font or DEFAULT_FONT)
|
||||||
|
@ -626,7 +629,6 @@ class Combo(Element):
|
||||||
if font is not None:
|
if font is not None:
|
||||||
style = create_style_from_font(font)
|
style = create_style_from_font(font)
|
||||||
self.QT_ComboBox.setStyleSheet(style)
|
self.QT_ComboBox.setStyleSheet(style)
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
def __del__(self):
|
def __del__(self):
|
||||||
|
@ -754,7 +756,7 @@ class Listbox(Element):
|
||||||
element_callback_quit_mainloop(self)
|
element_callback_quit_mainloop(self)
|
||||||
|
|
||||||
|
|
||||||
def Update(self, values=None, disabled=None):
|
def Update(self, values=None, disabled=None, set_to_index=None):
|
||||||
if values is not None:
|
if values is not None:
|
||||||
self.Values = values
|
self.Values = values
|
||||||
for i in range(self.QT_ListWidget.count()):
|
for i in range(self.QT_ListWidget.count()):
|
||||||
|
@ -764,6 +766,9 @@ class Listbox(Element):
|
||||||
self.QT_ListWidget.setDisabled(True)
|
self.QT_ListWidget.setDisabled(True)
|
||||||
elif disabled == False:
|
elif disabled == False:
|
||||||
self.QT_ListWidget.setDisabled(False)
|
self.QT_ListWidget.setDisabled(False)
|
||||||
|
if set_to_index is not None:
|
||||||
|
self.QT_ListWidget.setCurrentRow(set_to_index)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
def SetValue(self, values):
|
def SetValue(self, values):
|
||||||
|
@ -4478,6 +4483,10 @@ def PackFormIntoFrame(window, containing_frame, toplevel_win):
|
||||||
element.QT_ComboBox.currentIndexChanged.connect(element.QtCurrentItemChanged)
|
element.QT_ComboBox.currentIndexChanged.connect(element.QtCurrentItemChanged)
|
||||||
if element.Tooltip:
|
if element.Tooltip:
|
||||||
element.QT_ComboBox.setToolTip(element.Tooltip)
|
element.QT_ComboBox.setToolTip(element.Tooltip)
|
||||||
|
if not element.Readonly:
|
||||||
|
element.QT_ComboBox.setEditable(True)
|
||||||
|
if not element.AutoComplete:
|
||||||
|
element.QT_ComboBox.setAutoCompletion(True)
|
||||||
qt_row_layout.addWidget(element.QT_ComboBox)
|
qt_row_layout.addWidget(element.QT_ComboBox)
|
||||||
# ------------------------- OPTION MENU (Like ComboBox but different) element ------------------------- #
|
# ------------------------- OPTION MENU (Like ComboBox but different) element ------------------------- #
|
||||||
elif element_type == ELEM_TYPE_INPUT_OPTION_MENU:
|
elif element_type == ELEM_TYPE_INPUT_OPTION_MENU:
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
|
|
||||||
[![Downloads](http://pepy.tech/badge/pysimplegui)](http://pepy.tech/project/pysimplegui)
|
[![Downloads](http://pepy.tech/badge/pysimplegui)](http://pepy.tech/project/pysimplegui)
|
||||||
[![Downloads ](https://pepy.tech/badge/pysimplegui27)](https://pepy.tech/project/pysimplegui27)
|
[![Downloads ](https://pepy.tech/badge/pysimplegui27)](https://pepy.tech/project/pysimplegui27)
|
||||||
|
[![Downloads](https://pepy.tech/badge/pysimpleguiqt)](https://pepy.tech/project/pysimpleguiqt)
|
||||||
![Documentation Status](https://readthedocs.org/projects/pysimplegui/badge/?version=latest)
|
![Documentation Status](https://readthedocs.org/projects/pysimplegui/badge/?version=latest)
|
||||||
![Awesome Meter](https://img.shields.io/badge/Awesome_meter-100-yellow.svg)
|
![Awesome Meter](https://img.shields.io/badge/Awesome_meter-100-yellow.svg)
|
||||||
![Python Version](https://img.shields.io/badge/Python-2.7_3.x-yellow.svg)
|
![Python Version](https://img.shields.io/badge/Python-2.7_3.x-yellow.svg)
|
||||||
|
@ -33,7 +34,7 @@
|
||||||
|
|
||||||
![Python Version](https://img.shields.io/badge/PySimpleGUI_For_Python_2.7_Version-1.16.0-blue.svg?longCache=true&style=for-the-badge)
|
![Python Version](https://img.shields.io/badge/PySimpleGUI_For_Python_2.7_Version-1.16.0-blue.svg?longCache=true&style=for-the-badge)
|
||||||
|
|
||||||
![Python Version](https://img.shields.io/badge/PySimpleGUIQt_For_Python_3.x_Version-01.17.0-orange.svg?longCache=true&style=for-the-badge)
|
![Python Version](https://img.shields.io/badge/PySimpleGUIQt_For_Python_3.x_Version-0.19.0-orange.svg?longCache=true&style=for-the-badge)
|
||||||
|
|
||||||
[Announcements of Latest Developments](https://github.com/MikeTheWatchGuy/PySimpleGUI/issues/142)
|
[Announcements of Latest Developments](https://github.com/MikeTheWatchGuy/PySimpleGUI/issues/142)
|
||||||
|
|
||||||
|
@ -3937,7 +3938,7 @@ From the start of the PSG project, tkinter was not meant to be the only underlyi
|
||||||
|
|
||||||
|
|
||||||
## Author
|
## Author
|
||||||
MikeTheWatchGuy
|
MikeB
|
||||||
|
|
||||||
## Demo Code Contributors
|
## Demo Code Contributors
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
|
|
||||||
[![Downloads](http://pepy.tech/badge/pysimplegui)](http://pepy.tech/project/pysimplegui)
|
[![Downloads](http://pepy.tech/badge/pysimplegui)](http://pepy.tech/project/pysimplegui)
|
||||||
[![Downloads ](https://pepy.tech/badge/pysimplegui27)](https://pepy.tech/project/pysimplegui27)
|
[![Downloads ](https://pepy.tech/badge/pysimplegui27)](https://pepy.tech/project/pysimplegui27)
|
||||||
|
[![Downloads](https://pepy.tech/badge/pysimpleguiqt)](https://pepy.tech/project/pysimpleguiqt)
|
||||||
![Documentation Status](https://readthedocs.org/projects/pysimplegui/badge/?version=latest)
|
![Documentation Status](https://readthedocs.org/projects/pysimplegui/badge/?version=latest)
|
||||||
![Awesome Meter](https://img.shields.io/badge/Awesome_meter-100-yellow.svg)
|
![Awesome Meter](https://img.shields.io/badge/Awesome_meter-100-yellow.svg)
|
||||||
![Python Version](https://img.shields.io/badge/Python-2.7_3.x-yellow.svg)
|
![Python Version](https://img.shields.io/badge/Python-2.7_3.x-yellow.svg)
|
||||||
|
@ -33,7 +34,7 @@
|
||||||
|
|
||||||
![Python Version](https://img.shields.io/badge/PySimpleGUI_For_Python_2.7_Version-1.16.0-blue.svg?longCache=true&style=for-the-badge)
|
![Python Version](https://img.shields.io/badge/PySimpleGUI_For_Python_2.7_Version-1.16.0-blue.svg?longCache=true&style=for-the-badge)
|
||||||
|
|
||||||
![Python Version](https://img.shields.io/badge/PySimpleGUIQt_For_Python_3.x_Version-01.17.0-orange.svg?longCache=true&style=for-the-badge)
|
![Python Version](https://img.shields.io/badge/PySimpleGUIQt_For_Python_3.x_Version-0.19.0-orange.svg?longCache=true&style=for-the-badge)
|
||||||
|
|
||||||
[Announcements of Latest Developments](https://github.com/MikeTheWatchGuy/PySimpleGUI/issues/142)
|
[Announcements of Latest Developments](https://github.com/MikeTheWatchGuy/PySimpleGUI/issues/142)
|
||||||
|
|
||||||
|
@ -3937,7 +3938,7 @@ From the start of the PSG project, tkinter was not meant to be the only underlyi
|
||||||
|
|
||||||
|
|
||||||
## Author
|
## Author
|
||||||
MikeTheWatchGuy
|
MikeB
|
||||||
|
|
||||||
## Demo Code Contributors
|
## Demo Code Contributors
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue