Python Forum
How to use relative positioning in my program?
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
How to use relative positioning in my program?
#1
Hello everyone, I'm pretty new to Python in generel (started the course in university like 1 month ago) and I found it quite interesting to finally be able to create my very own program with a GUI. I found out how to export it as a normal .exe too and in general the program works great but I have no idea how to convert absolute to relative positioning in Python (wxPython). I know a way from a game forum but I can't really use that I guess, anyway can this way somehow work in Python too? I'd appreciate it if someone shows me a simple and easy to understand example of how to convert the values so that when I enter full screen in my app it would resize and reposition everything to look normal (as it does in the small window). I also read here that I can {somehow} use a thing called 'sizers' but that looks extremely hard for now so it'd be better if you show me a way using "wx.GetDisplaySize()" as it's closer to that MTA forums link I gave (and wrote, it's in Lua) above^. This isn't really a homeword but it was an assignment in the lecture and I just want to create my first real program the right way-without any major bugs. Thanks for reading and hope you can shed some light on this matter, happy Easter :)

PS: Here's my whole app: https://pastebin.com/N0TiBi5J (Haven't done attempts as I really have no idea how to start with doing it, and didn't find anything that can help me around the Internet {it was too complex with sizers and there was pretty much nothing with the "wx.GetDisplaySize()" way})
Reply
#2
You really do want to use sizers, it's the only way to do it right.
It's also not as complicated as it looks.
This is actually a pretty good explanation with examples: https://wxpython.org/Phoenix/docs/html/s...rview.html
Reply
#3
(Apr-07-2018, 01:07 PM)Larz60+ Wrote: You really do want to use sizers, it's the only way to do it right.
It's also not as complicated as it looks.
This is actually a pretty good explanation with examples: https://wxpython.org/Phoenix/docs/html/s...rview.html

Thanks for the link, I read it and everything but...there are so many things that I get confused :\ Could you please make one button, text or whatever from my code to work as needed when window gets resized so I see it in action. I'll do it on all other things. It's easier to learn when you see a working code and then edit it and try out other stuff with it.
Reply
#4
post you code here and I'll take a look at it.
Paste bin is not the forum.
Reply
#5
(Apr-19-2018, 05:22 PM)Larz60+ Wrote: post you code here and I'll take a look at it.
Paste bin is not the forum.

Oops, here it is:
import wx
import time

class BMICalculator(wx.Frame):
	def __init__(self, parent, id):
		self.display_length_, self.display_height_ = wx.GetDisplaySize()
		wx.Frame.__init__(self, parent, id, "BMI Calculator")
		self.panel = wx.Panel(self)
		self.panel.SetBackgroundColour("#FFFFFF")
		self.Centre()
		self.info_text = wx.StaticText(self.panel, -1, "Enter your height and weight and press compute to see your BMI.", (20, 15))
		self.label_text = wx.StaticText(self.panel, -1, "Body Mass Index: ", (20, 50))
		self.result_text = wx.StaticText(self.panel, -1, "... kg/(m*m)", (120, 50))
		self.error_label = wx.StaticText(self.panel, -1, "Error(s): ", (290, 50))
		self.error_text = wx.StaticText(self.panel, -1, "", (269, 65))
		self.static_text_height = wx.StaticText(self.panel, -1, "Height:", (20, 90))
		self.height = wx.SpinCtrlDouble(self.panel, -1, pos = (65, 87), size = (60, -1), min = 0, max = 300)
		self.static_text_height_extra = wx.StaticText(self.panel, -1, "(in centimeters)", (130, 90))
		self.static_text_weight = wx.StaticText(self.panel, -1, "Weight:", (20, 130))
		self.weight = wx.SpinCtrlDouble(self.panel, -1, pos = (65, 127), size = (60, -1), min = 0, max = 300)
		self.static_text_weight_extra = wx.StaticText(self.panel, -1, "(in kilograms)", (130, 130))
		self.bmi_underweight = wx.StaticText(self.panel, -1, "Underweight = < 18.5", (253, 90))
		self.bmi_normal_weight = wx.StaticText(self.panel, -1, "Normal weight = 18.5-24.9", (239, 110))
		self.bmi_overweight = wx.StaticText(self.panel, -1, "Overweight = 25-29.9", (254, 130))
		self.bmi_obesity = wx.StaticText(self.panel, -1, "Obesity = > 30", (274, 150))
		self.button_compute = wx.Button(self.panel, label = "Compute", pos = (40, 170), size = (60, -1))
		self.button_compute.SetBackgroundColour((0, 255, 0))
		self.button_compute.Bind(wx.EVT_BUTTON, self.onCompute)
		self.button_refresh = wx.Button(self.panel, label = "Refresh", pos = (122, 170), size = (60, -1))
		self.button_refresh.SetBackgroundColour((255, 165, 0))
		self.button_refresh.Bind(wx.EVT_BUTTON, self.onRefresh)
		self.button_theme = wx.Button(self.panel, label = "Theme", pos = (203, 170), size = (60, -1))
		self.button_theme.SetBackgroundColour((0, 255, 255))
		self.button_theme.Bind(wx.EVT_BUTTON, self.onThemeChange)
		self.button_cancel = wx.Button(self.panel, label = "Close", pos = (285, 170), size = (60, -1))
		self.button_cancel.SetBackgroundColour((255, 0, 0))
		self.button_cancel.Bind(wx.EVT_BUTTON, self.onClose)
		self.isBlack = False
	
	def onCompute(self, event):
		if (self.compute_BMI(self.height.GetValue(), self.weight.GetValue()) == None):
			self.result_text.SetLabel("... kg/(m*m)")
		else:
			self.result_text.SetLabel(str(self.compute_BMI(self.height.GetValue(), self.weight.GetValue())) + " kg/(m*m)")
		self.button_compute.SetBackgroundColour((0, 0, 255))
		time.sleep(0.1)
		self.button_compute.SetBackgroundColour((0, 255, 0))
	
	def onRefresh(self, event):
		self.result_text.SetLabel("... kg/(m*m)")
		self.error_text.SetLabel("")
		self.height.SetValue(0)
		self.weight.SetValue(0)
		
	def onThemeChange(self, event):
		if (self.isBlack == False):
			self.panel.SetBackgroundColour("Black")
			self.info_text.SetForegroundColour((255, 255, 255))
			self.label_text.SetForegroundColour((255, 255, 255))
			self.result_text.SetForegroundColour((255, 255, 255))
			self.error_label.SetForegroundColour((255, 255, 255))
			self.error_text.SetForegroundColour((255, 255, 255))
			self.static_text_height.SetForegroundColour((255, 255, 255))
			self.static_text_height_extra.SetForegroundColour((255, 255, 255))
			self.static_text_weight.SetForegroundColour((255, 255, 255))
			self.static_text_weight_extra.SetForegroundColour((255, 255, 255))
			self.bmi_underweight.SetForegroundColour((255, 255, 255))
			self.bmi_normal_weight.SetForegroundColour((255, 255, 255))
			self.bmi_overweight.SetForegroundColour((255, 255, 255))
			self.bmi_obesity.SetForegroundColour((255, 255, 255))
			self.button_compute.SetForegroundColour((255, 255, 255))
			self.button_refresh.SetForegroundColour((255, 255, 255))
			self.button_theme.SetForegroundColour((255, 255, 255))
			self.button_cancel.SetForegroundColour((255, 255, 255))
			self.isBlack = True
		elif (self.isBlack == True):
			self.panel.SetBackgroundColour("White")
			self.info_text.SetForegroundColour((0, 0, 0))
			self.label_text.SetForegroundColour((0, 0, 0))
			self.result_text.SetForegroundColour((0, 0, 0))
			self.error_label.SetForegroundColour((0, 0, 0))
			self.error_text.SetForegroundColour((0, 0, 0))
			self.static_text_height.SetForegroundColour((0, 0, 0))
			self.static_text_height_extra.SetForegroundColour((0, 0, 0))
			self.static_text_weight.SetForegroundColour((0, 0, 0))
			self.static_text_weight_extra.SetForegroundColour((0, 0, 0))
			self.bmi_underweight.SetForegroundColour((0, 0, 0))
			self.bmi_normal_weight.SetForegroundColour((0, 0, 0))
			self.bmi_overweight.SetForegroundColour((0, 0, 0))
			self.bmi_obesity.SetForegroundColour((0, 0, 0))
			self.button_compute.SetForegroundColour((0, 0, 0))
			self.button_refresh.SetForegroundColour((0, 0, 0))
			self.button_theme.SetForegroundColour((0, 0, 0))
			self.button_cancel.SetForegroundColour((0, 0, 0))
			self.isBlack = False
		self.panel.Refresh()
		
	def onClose(self, event):
		self.Close(True)
		self.button_cancel.SetBackgroundColour((0, 0, 255))
		time.sleep(0.1)
		self.button_cancel.SetBackgroundColour((255, 0, 0))
	
	def errorZeroDivision(self):
		self.error_text.SetLabel("Division by zero")
	
	def compute_BMI(self, height, weight):
		self.error_text.SetLabel("")
		height_m = float(height) / 100
		if ((height_m * height_m) == 0):
			self.errorZeroDivision()
			return None
		BMI = weight / (height_m * height_m)
		return BMI
	
def main():
	app = wx.App()
	frame = BMICalculator(None, -1)
	frame.Show()
	app.MainLoop()
	
if __name__ == "__main__":
	main()
Reply
#6
Ok,
Looking at the application, there may be an easier way than using sizers (which would still work),
and that's the new wx.AUI manager ... Working on it, back soon
Reply
#7
Ok, this is more complicated than I originally thought.
It still involves combinations of horizontal and vertical sizers,
but I want to make sure I understand what you're trying to do
(I do understand that you want to eliminate the absolute x and y positions)
is that all, or do you want the individual widgets to resize in proportion when the
entire window is resized ...
Or just maintain balance between sides of the main frame
(An example would be the way the demo box is resized (if you have access to the demo)
Usually the entire widget sizes remain constant, and x and y positions change (or remain static).
Reply
#8
Here's an example (extracted from phoenix demo) that shows the various horizontal and vertical sizers,
and the results of using proportions to determine how to resize each widget.
Note that some remain static, and others expand with window expansion.

You should be able to use this as an example to apply to your application (which looks quite nice I might add).
import wx
import wx.lib.sized_controls as sc

class FormDialog(sc.SizedDialog):
    def __init__(self, parent, id=wx.ID_ANY):
        sc.SizedDialog.__init__(self, None, -1, "SizedForm Dialog",
                        style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER)

        pane = self.GetContentsPane()
        pane.SetSizerType("form")

        # row 1
        wx.StaticText(pane, -1, "Name")
        textCtrl = wx.TextCtrl(pane, -1, "Your name here")
        textCtrl.SetSizerProps(expand=True)

        # row 2
        wx.StaticText(pane, -1, "Email")
        emailCtrl = wx.TextCtrl(pane, -1, "")
        emailCtrl.SetSizerProps(expand=True)

        # row 3
        wx.StaticText(pane, -1, "Gender")
        wx.Choice(pane, -1, choices=["male", "female"])

        # row 4
        wx.StaticText(pane, -1, "State")
        wx.TextCtrl(pane, -1, size=(60, -1)) # two chars for state

        # row 5
        wx.StaticText(pane, -1, "Title")

        # here's how to add a 'nested sizer' using sized_controls
        radioPane = sc.SizedPanel(pane, -1)
        radioPane.SetSizerType("horizontal")
        radioPane.SetSizerProps(expand=True)

        # make these children of the radioPane to have them use
        # the horizontal layout
        wx.RadioButton(radioPane, -1, "Mr.")
        wx.RadioButton(radioPane, -1, "Mrs.")
        wx.RadioButton(radioPane, -1, "Dr.")
        # end row 5

        # add dialog buttons
        self.SetButtonSizer(self.CreateStdDialogButtonSizer(wx.OK | wx.CANCEL))

        # a little trick to make sure that you can't resize the dialog to
        # less screen space than the controls need
        self.Fit()
        self.SetMinSize(self.GetSize())

if __name__ == "__main__":
    app = wx.App(False)
    fd = FormDialog(app)
    fd.Show()
    app.MainLoop()
Reply
#9
Thanks a lot! I want the widgets and everything to remain in the same places as if the app is in the small window but just become bigger when it's maximized. I'll give this a shot a bit later though as this month (and probably next) I'm buried in exams.
Reply


Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020