appJar icon indicating copy to clipboard operation
appJar copied to clipboard

TTK Support

Open ghost opened this issue 7 years ago • 41 comments

Is there any chance you'd be willing to add ttk support, or accept a PR adding ttk support? I personally like the native look a lot more, and I'd love to use ttk widgets with appJar.

List of supported widgets (http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/ttk-widget-set.html)

Basic widgets:

  • [x] ttk.Label
  • [x] ttk.Button
  • [x] ttk.Entry
  • [x] ttk.Checkbutton
  • [x] ttk.Radiobutton
  • [x] ttk.Scale

And their other incantations:

  • [x] Buttons
  • [x] Labels
  • [x] Labelled Widgets

Others:

  • [x] ttk.Frame
  • [x] ttk.LabelFrame
  • [ ] ttk.Menubutton
  • [ ] ttk.PanedWindow
  • [ ] ttk.Scrollbar

Nice to haves:

  • [ ] OptionBox?

  • [x] Also, include support for additional ttk themes

ghost avatar Jul 09 '17 02:07 ghost

Definitely interested in adding this.

How do you envisage it working?

Perhaps just a flag that can be set to use ttk if available? This will then import ttk and replace any existing widgets with ttk widgets, as well as make any new widgets available?

Is ttk always part of a Python installation? I seem to remember having issues importing ttk when I first started appJar...

If a user wants ttk, then the config options might need to be changed too?

jarvisteach avatar Jul 09 '17 11:07 jarvisteach

I imagined using a flag, and then tk/ttk specific functions/options would check for the flag and then use the relevant options. I think the best way to set the flag would be either:

app = gui( useTtk=True )

Or:

app = gui()
app.useTtk()

I'm not sure if tk and ttk widgets can exist together, so if have to check that out.

The x86 Windows installer for python 3.6 has ttk by default, but when I get home I can check some Linux distros. Either way, I think using tk as the default and and requiring ttk to be explicitly asked for would be for the best.

Config options are the biggest issue with this. I remember bg, padx, and pady being the biggest culprits, but it won't be too hard to get the ttk widgets running properly, just some if..else statements checking for the useTtk flag.

EDIT: Fixed formatting

ghost avatar Jul 09 '17 16:07 ghost

Fully updated and (almost) clean VMs of Ubuntu 16.04 LTS 64 bit, Fedora 25 64 bit, and FreeBSD 64 bit all properly import tkinter, and ttk in python 2 and 3 after installing the necessary packages. It looks like every modern pre-built python is linked against tkinter >= 8.5

ghost avatar Jul 10 '17 02:07 ghost

Great, thanks for investigating that!

OK, I'll add the second option you mention above, and for now simply have that import ttk - that will override any existing widgets.

I'll leave it at that for the current scheduled release (already overdue) - unless it breaks the basic setup - then in the next release we can look at updating config functions, as well as exposing any other widgets/features.

jarvisteach avatar Jul 10 '17 19:07 jarvisteach

This doesn't really have any effect.

Need to change instantiation to actually be ttk.Button, etc....

jarvisteach avatar Aug 18 '17 06:08 jarvisteach

Check here for how to set ttk styles: http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/ttk-style-layer.html

And themes: http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/ttk-theme-layer.html

jarvisteach avatar Aug 18 '17 07:08 jarvisteach

Making progress - need to work out how to subclass using a switch for ttk (for SelectableLabel, AutoCompleteEntry, ajScale)- might not be possible...

Need to go through top-level frames, etc - make sure they are all ttk - might need to have ttk a constructor parameter to achieve this.

Need to look at scrollbars - on list boxes, scroll panes, etc

jarvisteach avatar Aug 18 '17 10:08 jarvisteach

Just a small note, you may want to use "clam" as default style on Linux, "aqua" for Mac and "vista" for Windows, these are all built-in so shouldn't cause any issues, you could slap it in a try/except to ignore failed style changes.

mpmc avatar Aug 18 '17 11:08 mpmc

Have a solution for subclassing:

  • in the ttkFlag function set two global variables - labelBase & frameBase
  • then use these when subclassing, creating GUI, etc

However, note that a lot of special classes rely heavily on non-ttk supported features - and can't use a ttk.Label

jarvisteach avatar Oct 01 '17 07:10 jarvisteach

The useTtk flag needs to be moved to the constructor - otherwise the base Frame can't be a ttk frame

jarvisteach avatar Oct 01 '17 07:10 jarvisteach

useTtk now available in constructor - the only benefit is that the entire GUI is in a ttk.Frame instead of Frame - gets rid of the white border.

jarvisteach avatar Oct 01 '17 09:10 jarvisteach

TextArea isn't supported by Ttk.

mark@mark-desktop2:~/dev/git/HS602/hs602util$ python3 gui.py --ttk default
Exception in Tkinter callback
Traceback (most recent call last):
  File "/usr/lib/python3.5/tkinter/__init__.py", line 1553, in __call__
    return self.func(*args)
  File "/usr/lib/python3.5/tkinter/__init__.py", line 599, in callit
    func(*args)
  File "/home/mark/.local/lib/python3.5/site-packages/appJar/appjar.py", line 1852, in __processEventQueue
    func(*args, **kwargs)
  File "gui.py", line 103, in error_win
    self.addScrolledTextArea('traceback')
  File "/home/mark/.local/lib/python3.5/site-packages/appJar/appjar.py", line 6883, in addScrolledTextArea
    text = self.__buildTextArea(title, self.getContainer(), True)
  File "/home/mark/.local/lib/python3.5/site-packages/appJar/appjar.py", line 6849, in __buildTextArea
    text.config(highlightbackground=self.__getContainerBg())
  File "/home/mark/.local/lib/python3.5/site-packages/appJar/appjar.py", line 3239, in __getContainerBg
    return self.getContainer()["bg"]
  File "/usr/lib/python3.5/tkinter/__init__.py", line 1337, in cget
    return self.tk.call(self._w, 'cget', '-' + key)
_tkinter.TclError: unknown option "-bg"
mark@mark-desktop2:~/dev/git/HS602/hs602util$ python3 gui.py --ttk default
Exception in Tkinter callback
Traceback (most recent call last):
  File "/usr/lib/python3.5/tkinter/__init__.py", line 1553, in __call__
    return self.func(*args)
  File "/usr/lib/python3.5/tkinter/__init__.py", line 599, in callit
    func(*args)
  File "/home/mark/.local/lib/python3.5/site-packages/appJar/appjar.py", line 1852, in __processEventQueue
    func(*args, **kwargs)
  File "gui.py", line 103, in error_win
    self.addTextArea('traceback')
  File "/home/mark/.local/lib/python3.5/site-packages/appJar/appjar.py", line 6871, in addTextArea
    text = self.__buildTextArea(title, self.getContainer())
  File "/home/mark/.local/lib/python3.5/site-packages/appJar/appjar.py", line 6849, in __buildTextArea
    text.config(highlightbackground=self.__getContainerBg())
  File "/home/mark/.local/lib/python3.5/site-packages/appJar/appjar.py", line 3239, in __getContainerBg
    return self.getContainer()["bg"]
  File "/usr/lib/python3.5/tkinter/__init__.py", line 1337, in cget
    return self.tk.call(self._w, 'cget', '-' + key)
_tkinter.TclError: unknown option "-bg"

mpmc avatar Oct 16 '17 09:10 mpmc

ValidationEntry using ttk errors :crying_cat_face: .

Exception in Tkinter callback
Traceback (most recent call last):
  File "/usr/lib/python3.6/tkinter/__init__.py", line 1702, in __call__
    return self.func(*args)
  File "/usr/lib/python3.6/tkinter/__init__.py", line 748, in callit
    func(*args)
  File "/home/mark/.local/lib/python3.6/site-packages/appJar/appjar.py", line 2058, in __processEventQueue
    func(*args, **kwargs)
  File "gui2.py", line 197, in result
    return self.manual()
  File "gui2.py", line 238, in manual
    self.addValidationEntry('addr', 0, 1)
  File "/home/mark/.local/lib/python3.6/site-packages/appJar/appjar.py", line 7370, in addValidationEntry
    ent = self.__buildValidationEntry(title, self.getContainer(), secret)
  File "/home/mark/.local/lib/python3.6/site-packages/appJar/appjar.py", line 7376, in __buildValidationEntry
    vFrame.config(background=self.__getContainerBg())
  File "/home/mark/.local/lib/python3.6/site-packages/appJar/appjar.py", line 3422, in __getContainerBg
    return self.getContainer()["bg"]
  File "/usr/lib/python3.6/tkinter/__init__.py", line 1486, in cget
    return self.tk.call(self._w, 'cget', '-' + key)
_tkinter.TclError: unknown option "-bg"

I like the use of validation alerting, but wouldn't it be easier (and less code?) to replace "setEntryValid", "setEntryInvalid", and "setEntryWaitingValidaiton" with a single function? That just flashes the entry (once) & inserts some text indicating the error - disappearing on click/text entry?

The use of the icons next to the entries is a nice touch but it kinda looks odd when you have your form neatly aligned and some are just standard entries. This could be solved with an addOptional(<Numeric>?)Entry.

mpmc avatar Nov 03 '17 23:11 mpmc

@mpmc - did a piece of work to get validation entries (sort of) working under ttk. Had to work out ttk styles, but at least now it doesn't crash. The border doesn't work on my mac - need to test on other platforms.

You're right - the validation entry could use lots of work. I will look at refactoring the set functions as part of the general add/set/get refactoring I'm currently doing, and will see what improvements can be made to its look & feel...

jarvisteach avatar Nov 11 '17 15:11 jarvisteach

@jarvisteach cool, I shall give it a go once I've redone this controller class & report any issues!

mpmc avatar Nov 11 '17 20:11 mpmc

Should include support for additional ttk themes: https://github.com/RedFantom/ttkthemes

jarvisteach avatar Nov 15 '17 20:11 jarvisteach

@jarvisteach I've been trying out ttk on the next release appJar branch, and have found some issues. The first one I encountered was when I used.setCheckbox("title", ticked=True), it would give me AttributeError: 'Checkbutton' object has no attribute 'select'. The second issue that I found was that when I used .zoomImage(), it would give me _tkinter.TclError: unknown option "-bg". I understand that ttk is still in beta, but I thought that it would be good if I let you know of these issues :)

cowsay652 avatar Nov 26 '17 20:11 cowsay652

These should both be resolved now, and do please keep them coming!

jarvisteach avatar Nov 27 '17 00:11 jarvisteach

@jarvisteach Here some more issues (yay!). This time, it's with .addMessage(). I get _tkinter.TclError: unknown option "-bg". Also, Internationalisation looks like it breaks when using ttk, as I get appJar:WARNING [Line 285->1139/changeLanguage]: Invalid config section: <Widget name here> for all the widgets that I have used.

cowsay652 avatar Nov 27 '17 12:11 cowsay652

Internationalisation looks to be a slightly bigger issue than just ttk - it's broken across the board, as result of the architecture change.

This bit no longer works: kind = vars(gui)[section] Need to replace that with a lookup in the enum, using the section name - might cause issues due to the capitalisation.

Also, the automated testing should have picked this up - need to actually run some assertions that text has been changed post language switch...

Will raise this/move this to another issue.

jarvisteach avatar Nov 27 '17 17:11 jarvisteach

@jarvisteach I've found that when using label frames and .setBg(), the background of the label frame doesn't change, with (as far as I've tested) only images and labels using the correct background colour. Also, regarding internationalisation, I get a warning that says that the Notebook widget is not supported (should this move to #71 ?) and this obviously leads to the notebook tabs not being translated.

cowsay652 avatar Nov 27 '17 20:11 cowsay652

@jarvisteach

Do you plan on making ttk widgets the default btw? Once they're all working that is.

mpmc avatar Nov 29 '17 09:11 mpmc

@jarvisteach Here are a couple of things that I found that aren't currently being themed by ttk: Spinboxes and Toolbars.

cowsay652 avatar Nov 29 '17 21:11 cowsay652

Hey @The-Sleepy-Penguin I don't think there is a ttk spinbox - http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/ttk-widget-set.html

What theming are you trying to achieve with it?

jarvisteach avatar Dec 02 '17 09:12 jarvisteach

@jarvisteach Oops. My mistake - I didn't realise that there wasn't a ttk spinbox (I was just looking for widgets that would let the user make a selection). Perhaps the Optionbox should be replaced by the Combobox for ttk? And another thing - Radiobuttons in ttk don't respond to .setBg (along with Labelframes).

Edit: After a quick search I found this for the ttk spinbox. It looks like it uses the buttons from the ttk scrollbar to change the selection.

cowsay652 avatar Dec 02 '17 11:12 cowsay652

@jarvisteach I've read the next_release docs and found how to change the background of most things, but the label in the LabelFrame doesn't change colour when I do: program.ttkStyle.configure("TLabel", background="white"), and I can't find the name for the checkbox layout, as I've tried to use TCheck, TCheckbox and TCheckBox but all return Layout xxx not found.

Also, I noticed a typo in the docs - with the code examples, you put background= as backgroun= :P

cowsay652 avatar Dec 17 '17 13:12 cowsay652

Hi @The-Sleepy-Penguin could you give me some sample code to test out...

jarvisteach avatar Dec 18 '17 18:12 jarvisteach

@jarvisteach Here is some code that demonstrates the issue with Label Frames and Checkboxes:

from appJar import gui

with gui("appJar", useTtk=True) as app:

    app.ttkStyle.configure("TFrame", background="blue")
    app.ttkStyle.configure("TLabel", background="blue")
    app.ttkStyle.configure("TCheckBox", background="blue")
    app.ttkStyle.configure("TCheck", background="blue")
    app.setBg("blue")

    with app.labelFrame("Text"):
        app.setLabelFrameStyle("Text", "TFrame")
        app.addCheckBox("Option here...")
        app.setCheckBoxStyle("Option here...", "TCheckBox")

    app.addCheckBox("Another option...")
    app.setCheckBoxStyle("Another option...", "TCheck")

And here is the result:

capture

Hope this helps :)

cowsay652 avatar Dec 18 '17 22:12 cowsay652

OK, had a little play, try these:

  • app.ttkStyle.configure("TCheckbutton", background="blue")
  • app.ttkStyle.configure("TLabelframe", background="blue")
  • app.ttkStyle.configure('TLabelframe.Label', background='blue')

These set the default styles for the widgets, so you should't need to call .set XXX Style()

I've also discovered this:

  • app.ttkStyle.configure('.', background="blue")

ttk styles inherit from one another, so setting background on . will be inherited by all widgets.

I'm going to use this in appJar...

jarvisteach avatar Dec 18 '17 23:12 jarvisteach

@jarvisteach Thanks! Those worked a charm.

cowsay652 avatar Dec 19 '17 18:12 cowsay652