HyperlinkCtrl text centre not working on windows

I have an app with a status bar at the bottom with two hypherlinks separated by a spacer. Each of the hypherlinks have the text centred. They are contained within a horizontal sizer.

The text does centre ok on macOS, but not on Windows (Win 10).

https://wxpython.org/Phoenix/docs/html/wx.adv.HyperlinkCtrl.html

Reading the docs says align centre is not supported under windows :frowning: It also says align right is also not supported. However my tests show that align right does in fact work :slight_smile:

I’m wondering why does align right work, but not align centre? Is there a bug somewhere or just Windows being Windows?

Can align centre be made to work somehow? Can I fake it (emulate it somehow)? Maybe spacers either side that expand, but the hyperlink widgets not expand?

Thanks, Brendan.

There are two aspects of alignment at play here which need to be considered.

The first is alignment within the widget itself. If the widget is sized to be just large enough to display it’s text, then there is no room to move the origin of the text around in order to align it visually within the widget’s size. If the widget is larger than its minimum needs then it does have space to play with and can change the origin of the text it draws. For the HyperLinkCtrl that is handled in its base class, here.

The other aspect is what alignment the sizer is able to do. You can think of this as alignment outside of the widget itself. In other words, if the sizer algorithm and item flags result in a space for the item being larger than the best size of the widget then the sizer is able to move the widget around within that allocated space based on the alignment flags. Using the WIT can help visualize how the layout is being done, as well as the size allocated by the sizer to the items it is managing.

Yes, that can be a useful way to manage things like this in some cases. But understanding the alignment info above may result in a better implementation.

Thanks Robin. I did most of what you are hinting at already. i.e. put two spacers in sizers on the left side of one of the hypertextctrl widgets, and on the right side of the other. The spacers have proportion set to 1 and htc widgets have proportion set to 0. there is also a fixed size spacer in between the htc widgets. It looks ok, but not perfect as the text for each htc is not the same.

However, after reading your response, it should work nicely if I force the two htc widgets to have the same size (either through using proportion = 1+ or programatically setting them both to the max of each other’s size), and then cetering the htc within the sizer.

But being curious, why does the align centre style not work on the htc itself (on Windows), but works ok on Mac?

I tried using the sizers but it didn’t work. Then I discovered the wxSHAPED flag and that made all the difference.

Without wxSHAPED, the hyperlinkctrl (or other widgets such as wxStaticText) would be sized to fit the sizer slot and auto expand if proportion >= 1.

With wxSHAPED, the widget is set to the minimum size, and then the sizer alignment styles can position the widget within the sizer slot.

BTW, I’m using wxglade for the layout if you hadn’t guessed already :slight_smile:
I hadn’t heard of WIT before. It looks interesting and useful too !!

If you can make a small runnable sample that demonstrates the problem I’d be interested in seeing it.

Here is the code that shows the issue (note: using python3.7, wxPython 4.0.6).

There are three horizontal sizers (with pad of 5).

  • Each horizontal sizer has 3 hyperlinkctrl widgets, set to align left, centre and right respectively (pad of 5).
  • The first sizer has widgets without wxSHAPED and proportion=1.
  • The second sizer has widgets with wxSHAPED and proportion=0.
  • The third sizer has widgets with wxSHAPED and proportion=1 (directly set in python file as wxglade wont allow it).

Interestingly, the clipping of the hypherlinkctrl happens when padding is set and proportion=0, but not when proportion=1.

Here is the python code.

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
#
# generated by wxGlade 0.9.9pre on Tue Sep  3 10:15:07 2019
#

import wx
import wx.adv

# begin wxGlade: dependencies
# end wxGlade

# begin wxGlade: extracode
# end wxGlade


class MyFrame(wx.Frame):
    def __init__(self, *args, **kwds):
        # begin wxGlade: MyFrame.__init__
        kwds["style"] = kwds.get("style", 0) | wx.DEFAULT_FRAME_STYLE
        wx.Frame.__init__(self, *args, **kwds)
        self.SetSize((436, 302))
        self.SetTitle("frame")
        
        sizer_1 = wx.BoxSizer(wx.VERTICAL)
        
        sizer_2 = wx.StaticBoxSizer(wx.StaticBox(self, wx.ID_ANY, "without wxSHAPED"), wx.HORIZONTAL)
        sizer_1.Add(sizer_2, 0, wx.ALL | wx.EXPAND, 5)
        
        self.hyperlink_1 = wx.adv.HyperlinkCtrl(self, wx.ID_ANY, "hyperlink_1", "")
        sizer_2.Add(self.hyperlink_1, 1, wx.ALIGN_CENTER | wx.ALL, 5)
        
        self.hyperlink_2 = wx.adv.HyperlinkCtrl(self, wx.ID_ANY, "hyperlink_2", "", style=wx.adv.HL_ALIGN_CENTRE)
        sizer_2.Add(self.hyperlink_2, 1, wx.ALIGN_CENTER | wx.ALL, 5)
        
        self.hyperlink_3 = wx.adv.HyperlinkCtrl(self, wx.ID_ANY, "hyperlink_3", "", style=wx.adv.HL_ALIGN_RIGHT)
        sizer_2.Add(self.hyperlink_3, 1, wx.ALIGN_CENTER | wx.ALL, 5)
        
        sizer_3 = wx.StaticBoxSizer(wx.StaticBox(self, wx.ID_ANY, "with wxSHAPED, proportion=0"), wx.HORIZONTAL)
        sizer_1.Add(sizer_3, 0, wx.ALL | wx.EXPAND, 5)
        
        self.hyperlink_4 = wx.adv.HyperlinkCtrl(self, wx.ID_ANY, "hyperlink_4", "")
        sizer_3.Add(self.hyperlink_4, 0, wx.ALIGN_CENTER | wx.ALL | wx.SHAPED, 5)
        
        self.hyperlink_5 = wx.adv.HyperlinkCtrl(self, wx.ID_ANY, "hyperlink_5", "", style=wx.adv.HL_ALIGN_CENTRE)
        sizer_3.Add(self.hyperlink_5, 0, wx.ALIGN_CENTER | wx.ALL | wx.SHAPED, 0)
        
        self.hyperlink_6 = wx.adv.HyperlinkCtrl(self, wx.ID_ANY, "hyperlink_6", "", style=wx.adv.HL_ALIGN_RIGHT)
        sizer_3.Add(self.hyperlink_6, 0, wx.ALIGN_CENTER | wx.ALL | wx.SHAPED, 5)
        
        sizer_4 = wx.StaticBoxSizer(wx.StaticBox(self, wx.ID_ANY, "with wxSHAPED, proportion=1"), wx.HORIZONTAL)
        sizer_1.Add(sizer_4, 0, wx.ALL | wx.EXPAND, 5)
        
        #!
        #! NOTE: manually added proportion=1 as wxglade resets it to zero if wxSHAPED is selected !!
        #!
        proportion = 1

        self.hyperlink_7 = wx.adv.HyperlinkCtrl(self, wx.ID_ANY, "hyperlink_7", "")
        sizer_4.Add(self.hyperlink_7, proportion, wx.ALIGN_CENTER | wx.ALL | wx.SHAPED, 5)
        
        self.hyperlink_8 = wx.adv.HyperlinkCtrl(self, wx.ID_ANY, "hyperlink_8", "", style=wx.adv.HL_ALIGN_CENTRE)
        sizer_4.Add(self.hyperlink_8, proportion, wx.ALIGN_CENTER | wx.ALL | wx.SHAPED, 0)
        
        self.hyperlink_9 = wx.adv.HyperlinkCtrl(self, wx.ID_ANY, "hyperlink_9", "", style=wx.adv.HL_ALIGN_RIGHT)
        sizer_4.Add(self.hyperlink_9, proportion, wx.ALIGN_CENTER | wx.ALL | wx.SHAPED, 5)
        
        self.SetSizer(sizer_1)
        
        self.Layout()
        # end wxGlade

# end of class MyFrame

class MyApp(wx.App):
    def OnInit(self):
        self.frame = MyFrame(None, wx.ID_ANY, "")
        self.SetTopWindow(self.frame)
        self.frame.Show()
        return True

# end of class MyApp

if __name__ == "__main__":
    test_hypherlinkctrl = MyApp(0)
    test_hypherlinkctrl.MainLoop()

This is the wxglade project file.

<?xml version="1.0"?>
<!-- generated by wxGlade 0.9.9pre on Tue Sep  3 10:15:06 2019 -->

<application class="MyApp" encoding="UTF-8" for_version="3.0" header_extension=".h" indent_amount="4" indent_symbol="space" is_template="0" language="python" mark_blocks="1" name="test_hypherlinkctrl" option="0" overwrite="1" path="test_hyperlinkctrl.py" source_extension=".cpp" top_window="frame" use_gettext="0" use_new_namespace="1">
    <object class="MyFrame" name="frame" base="EditFrame">
        <size>436, 302</size>
        <title>frame</title>
        <style>wxDEFAULT_FRAME_STYLE</style>
        <object class="wxBoxSizer" name="sizer_1" base="EditBoxSizer">
            <orient>wxVERTICAL</orient>
            <object class="sizeritem">
                <option>0</option>
                <border>5</border>
                <flag>wxALL|wxEXPAND</flag>
                <object class="wxStaticBoxSizer" name="sizer_2" base="EditStaticBoxSizer">
                    <orient>wxHORIZONTAL</orient>
                    <label>without wxSHAPED</label>
                    <object class="sizeritem">
                        <option>1</option>
                        <border>5</border>
                        <flag>wxALL|wxALIGN_CENTER</flag>
                        <object class="wxHyperlinkCtrl" name="hyperlink_1" base="EditHyperlinkCtrl">
                            <label>hyperlink_1</label>
                            <attribute>1</attribute>
                        </object>
                    </object>
                    <object class="sizeritem">
                        <option>1</option>
                        <border>5</border>
                        <flag>wxALL|wxALIGN_CENTER</flag>
                        <object class="wxHyperlinkCtrl" name="hyperlink_2" base="EditHyperlinkCtrl">
                            <style>wxHL_ALIGN_CENTRE</style>
                            <label>hyperlink_2</label>
                            <attribute>1</attribute>
                        </object>
                    </object>
                    <object class="sizeritem">
                        <option>1</option>
                        <border>5</border>
                        <flag>wxALL|wxALIGN_CENTER</flag>
                        <object class="wxHyperlinkCtrl" name="hyperlink_3" base="EditHyperlinkCtrl">
                            <style>wxHL_ALIGN_RIGHT</style>
                            <label>hyperlink_3</label>
                            <attribute>1</attribute>
                        </object>
                    </object>
                </object>
            </object>
            <object class="sizeritem">
                <option>0</option>
                <border>5</border>
                <flag>wxALL|wxEXPAND</flag>
                <object class="wxStaticBoxSizer" name="sizer_3" base="EditStaticBoxSizer">
                    <orient>wxHORIZONTAL</orient>
                    <label>with wxSHAPED, proportion=0</label>
                    <object class="sizeritem">
                        <option>0</option>
                        <border>5</border>
                        <flag>wxALL|wxALIGN_CENTER|wxSHAPED</flag>
                        <object class="wxHyperlinkCtrl" name="hyperlink_4" base="EditHyperlinkCtrl">
                            <label>hyperlink_4</label>
                            <attribute>1</attribute>
                        </object>
                    </object>
                    <object class="sizeritem">
                        <option>0</option>
                        <border>0</border>
                        <flag>wxALL|wxALIGN_CENTER|wxSHAPED</flag>
                        <object class="wxHyperlinkCtrl" name="hyperlink_5" base="EditHyperlinkCtrl">
                            <style>wxHL_ALIGN_CENTRE</style>
                            <label>hyperlink_5</label>
                            <attribute>1</attribute>
                        </object>
                    </object>
                    <object class="sizeritem">
                        <option>0</option>
                        <border>5</border>
                        <flag>wxALL|wxALIGN_CENTER|wxSHAPED</flag>
                        <object class="wxHyperlinkCtrl" name="hyperlink_6" base="EditHyperlinkCtrl">
                            <style>wxHL_ALIGN_RIGHT</style>
                            <label>hyperlink_6</label>
                            <attribute>1</attribute>
                        </object>
                    </object>
                </object>
            </object>
            <object class="sizeritem">
                <option>0</option>
                <border>5</border>
                <flag>wxALL|wxEXPAND</flag>
                <object class="wxStaticBoxSizer" name="sizer_4" base="EditStaticBoxSizer">
                    <orient>wxHORIZONTAL</orient>
                    <label>with wxSHAPED, proportion=1</label>
                    <object class="sizeritem">
                        <option>0</option>
                        <border>5</border>
                        <flag>wxALL|wxALIGN_CENTER|wxSHAPED</flag>
                        <object class="wxHyperlinkCtrl" name="hyperlink_7" base="EditHyperlinkCtrl">
                            <label>hyperlink_7</label>
                            <attribute>1</attribute>
                        </object>
                    </object>
                    <object class="sizeritem">
                        <option>0</option>
                        <border>0</border>
                        <flag>wxALL|wxALIGN_CENTER|wxSHAPED</flag>
                        <object class="wxHyperlinkCtrl" name="hyperlink_8" base="EditHyperlinkCtrl">
                            <style>wxHL_ALIGN_CENTRE</style>
                            <label>hyperlink_8</label>
                            <attribute>1</attribute>
                        </object>
                    </object>
                    <object class="sizeritem">
                        <option>0</option>
                        <border>5</border>
                        <flag>wxALL|wxALIGN_CENTER|wxSHAPED</flag>
                        <object class="wxHyperlinkCtrl" name="hyperlink_9" base="EditHyperlinkCtrl">
                            <style>wxHL_ALIGN_RIGHT</style>
                            <label>hyperlink_9</label>
                            <attribute>1</attribute>
                        </object>
                    </object>
                </object>
            </object>
        </object>
    </object>
</application>

Hope that helps.

Brendan.

I didn’t read the original message closely enough, and assumed you were talking about the HyperlinkCtrl class in the wx.lib.agw.hyperlink module. So my comment about the alignment implementation above does not apply.

On Windows the wx.adv.HyperlinkCtrl is a wrapper around a native MSW control so the differences you’re seeing between OSX and Windows are due to 2 different implementations. It looks like the native control on Windows does not have a style flag for aligning in the center, just the default of aligning to the left, and a LWS_RIGHT flag for aligning to the right. So if you need center alignment with this control then you’ll need to do it with sizer flags or by using spacers.

The documentation does state that the style is not supported on Windows:

Ok. I didn’t realise there was a wx.lib.hyperlink module. I might take a look at that. It seems wxglade uses the adv.HypherLinkCtrl.

This page says align right is not supported at all on Windows (but it seems that it is), so maybe a documentation error.

https://wxpython.org/Phoenix/docs/html/wx.adv.HyperlinkCtrl.html

Yep, I think that’s a docs error.

That’s the development build of the docs (4.1.0) anyway. For the 4.0.x releases you should be using the docs at https://docs.wxpython.org/