Situation:
I'm making a software that has to be full screen
It is all UIs and interfaces.
I want it to work on computers with screens that have different resolutions - So I need the GUI to adjust to the screen size: text will be smaller if the screen resolution is smaller, but it will still be in the middle of the screen
I've tried not using numbers in deciding the position of the text, but instead getting the screen resolution, and multiplying it
Problem:
The text is not getting smaller.
Question:
Is there an easy solution for my problem? Is there a module in python for this purpose? I'm currently using WxPython but I'm open to use any other GUI module.
def Title(object):
(sizeX, sizeY) = object.GetSize()
(displayX, displayY) = wx.GetDisplaySize()
print(displayX)
print(displayY)
print(sizeX)
print(sizeY)
object.SetPosition((displayX/2 - sizeX/2, displayY*0.01))
To adjust the text size to be appropriate to the screen size, you would have to define a custom font size.
Although I suspect that the default font size will already be roughly correct, as the user will have set the system font size, based on the screen size.
You can get the current font size as follows:
self.font = wx.SystemSettings.GetFont(wx.SYS_SYSTEM_FONT)
point_size = self.font.GetPointSize()
Define a new, appropriate, font size based on the result from wx.GetDisplaySize():
self.font.SetPointSize(new size)
Then use SetFont(font) on the items in your UI:
self.panel.SetFont(self.font)
Related
Renpy uses a lot of python and custom made code, in order to show text that is displayed on screen using the say statement.
After running into some troubles with the nvl mode within renpy, I found it necessary to know how many lines are going to be displayed on screen (taking into account the font size, naturally and the size of the text window).
So my question:
As I didn't find anything in the documentation in regards to that, I'm wondering if there is any command or other possibility to precalculate the height of a text that is to be displayed?
get_virtual_layout() is part of class Text in text.py.
I copied this from text.py:
# Find the virtual-resolution layout.
virtual_layout = self.get_virtual_layout()
# The laid-out size of this Text.
vw, vh = virtual_layout.size
This looks promising, I think.
With the virtual text size (width, height) you could possibly calculate the lines of text by using the text window size (width, height).
pseudo code:
lines = int(vw/text_window.width)
#the text height would then be
text_height_needed = int(lines*vh)
# does it fit in completely
complete_text_in_window = text_window.height >= text_height_needed
# visible lines
visible_lines = int(text_window.height/vh)
Also, it is worth to take a deeper look at text.py(e.g. def render(self, width, height, st, at)), in order to get to know the use of virtual_layout.
I hope it helps somehow.
Update:
def render(...) initializes the virtual layouts, so get_virtual_layout() is not None anymore, but represents an instance of Layout() with scaled width and height.
I create script for playblast. I need some HUD data over my video like a user and scene name, fps and current frame...
First i try HUD created by headsUpDisplay() is good, but not have a background... I change color of HUD labels but sometimes they are not readable without a background.
cmds.headsUpDisplay('HUDObjectSceneName', label='label TEXT',
section=2, block=0, blockSize='large',
dfs='large', labelFontSize='large')
Second i try use HUD buttons created by hudButton() - they have a background. But one of my label - is current time. headsUpDisplay() have 'command' to refresh and change label text. But hudButton() does not have this functionality.
label = 'FPS: 25 FRAME:'
cmds.hudButton('HUDHelloButton3', s=9, b=0, vis=1, l=label,
bw=blockLen(label), lfs='large')
cmds.headsUpDisplay('HUDCurentFrame', label=label,
section=9, block=0, blockSize='large', dfs='large',
labelFontSize='large', atr=True,
command=lambda: cmds.currentTime(query=True))
hudButton() have second trouble - width of button is set manually. and when i want long label i need to calculate label width. but HUD font is not fixed and i don't know how right calculate a label width in pixels. After some experiments i create this function to calculate width. It made rough, but at least as that:
def blockLen(label):
FONT_WIDTH = 8
THIN_WIDTH = 6
BLOCK_ADD = 10
thin_symbol = ' :,.!i[];:\'"|-'
sum = BLOCK_ADD
for x in label:
sum += THIN_WIDTH if x in thin_symbol else FONT_WIDTH
return sum
I need HUD label with background and dynamic data like a current frame. But i can't find another way how create it?
ps. I try to use scriptJob() to change HUD button label when time changed. But its not worked with playblast...
scriptJobs do not execute when animations are playing. If you really need to update the hud during playback you can trigger your update from inside an expression. You'll have to call it from mel, unfortunately. And keep it as light as possible, it will slowdown interactive playback for anybody viewing the animation.
You might want to dynamically create the expression before playblasts and then delete it right afterwards so you don't leave it lying around to bother your animators.
You can also get out of using HUD buttons by creating an image plane set to an appropriate color.
One part of my problem i decided to. I don't find how to update button directly. I create headsUpDisplay() without label - he is able to updated. And i forced him to change the text on my hudButton()
def frame_label():
label = 'FPS: 24 FRAME: %s' % cmds.currentTime(query=True)
cmds.hudButton('HUDCurentFrame', e=True, l=label)
# bottom-right: FPS and current frame info
cmds.headsUpDisplay('HUDCurentFrameInvisible', label='',
section=9, block=1, blockSize='large', dfs='large',
labelFontSize='large', command=frame_label, atr=True)
cmds.hudButton('HUDCurentFrame', s=9, b=0, vis=1, l='', bw=200, lfs='large')
But second part of my problem not solved. I cant calculate text size in pixels. The correct solution is to get from the Maya which font is used for HUD. And then i can use wx library to calculate width of text using font name...
But how to get font data (name, size and decorations) from Maya?
to your second problem:
i was able to find the needed font data (only name, size) but its not really accurate(more hacking, no voting needed), if you change the view port renderer to ViewPort 2.0 and than
and changing the sizes of the font you will get the Error (nor on the default renderer):
# small display ui font size and display ui size
cmds.displayPref(sfs=9, dfs=10) #font size
cmds.savePref()
Failed trying to load font: -*-helvetica-bold-normal-*-9-*-*-*-*-*-iso8859-1
so the used font is helvetica bold and the size is relativ(you own input or the default value like cmds.optionVar(q="defaultFontSize"))
Does anyone know how Kivy renders text in different fonts?
I have labels with text at 16sp.
On a tablets with screen sizes (1024, 552) and (2048, 1536) it works perfectly (width/height ratios 1.855 and 1.333 respectively)
On the pc with screen size (1280, 720) (ratio 1.778) it also displays perfectly, but on a phone with this screen size the letters are truncated
The only difference here is the physical size of the device. It thus appears, that Kivy text is not rendered according to some algorithm based on pixels, but takes into account the physical size of the screen
Is there any way to determine the physical size in Kivy? and hence allow me to adjust font size accordingly. The text appears correctly on the phone (small device) if I use a smaller (10sp) font size, but then it appears too small on the larger devices.
Yes, you can determine the physical size of screen with kivy -
You could simply use this Module:
(from kivy.core.window import Window)
and then determine sizes by writing this:
(Window.size)
Check this code out (this code determines screen physical sizes on a simple label):
⬇️⬇️
from kivy.app import App
from kivy.uix.label import Label
from kivy.core.window import Window
class MyApp(App):
def build(self):
window_sizes=Window.size
return Label(text="screen sizes= "+str(window_sizes))
MyApp().run()
It is possible to obtain the screen sizes, but you'll need to install plyer and before packaging also patch it, so that you could access the info.
Or just use the plain pyjnius and access android.util.DisplayMetrics with autoclass.
From what I am understanding, you are having issues displaying your text properly, over multiple devices. Now, I do not think that you can get the devices actual dimensions through Kivy itself, but with plain old python, you can.
An Example in Python:
import gtk
window = gtk.Window()
screen = window.get_screen()
print "screen size: %d x %d" % (
gtk.gdk.screen_width(),gtk.gdk.screen_height())
The Code above will print out the screen heigh and width, or resolution, for you to use.
To store them in variables instead:
import gtk
window = gtk.Window()
screen = window.get_screen()
ScreenWidth = gtk.gdk.screen_width()
ScreenHeight = gtk.gdk.screen_height()
# And to prove it worked (You would not want to include this part in code
#########################################################################
print str(ScreenWidth) + 'x' + str(ScreenHeight)
Now that you have those variables, you can use them in your .kv file, by pulling them from a python file, or implementing the whole function directly into your Kivy Code somehow.
From: https://kivy.org/docs/api-kivy.metrics.html we learn that 'sp' is the scale independent pixel size. Thus it includes the pixel density already and the font size appears the same on each device (at least should).
The reason, why your font is clipped is because of the size of the container. You also should also give the desired size, like in this example (note: if you want a secific height, you must include the size_hint_y: None argument)
TextInput:
id: text_input
size_hint_y: None
height: '30sp'
multiline: False
What I ended up doing is maximizing my window to get the maximum allowed non-full screen size, then reading that size. I actually used it to center a smaller window on screen:
#-- maximize first, to get the screen size, minus any OS toolbars
Window.maximize()
maxSize = Window.system_size
#-- set the actual window size, to be slightly smaller than full screen
desiredSize = (maxSize[0]*0.9, maxSize[1]*0.9)
Window.size = desiredSize
#-- center the window
Window.left = (maxSize[0] - desiredSize[0])*0.5
Window.top = (maxSize[1] - desiredSize[1])*0.5
Note that by maximizing my window first, I am getting the maximum allowed size, less any operating system's toolbars etc., i.e., the size that the window has when you press the maximize button.
Is there a 'standard' way of ensuring that the displayed window is wide enough to display the window title?
import tkinter as tk
root = tk.Tk()
root_f = tk.Frame(root)
root.title('Long Window Title Containing Much Text')
text_f = tk.Frame(root_f)
text_l = tk.Label(text_f, text='Short text')
root_f.grid()
text_f.grid()
text_l.grid()
root.geometry('+{}+{}'.format(100, 100))
root.mainloop()
root.quit()
When I use the winfo method to get the width of the root (or text) frames they give the size of the text not the size of a window wide enough to display the whole window title.
I know it has to be something simple, but I can't see it.
Thanks
No, there is no standard way. Tkinter has no way of knowing how long the title is on the titlebar. The OS / window manager has completely control of that portion of the window and doesn't expose any platform-independent way of getting at that information.
You would have to know not only the font used by the OS for window titles, but also whether there were any other decorations (eg: buttons, images, etc) that appear in the title area.
If you're fine with making assumptions that the font is the same as the default tkinter font, you can use tkinter's ability to measure the length of a string in a given font with the measure method of a font object.
I am new to Python and have been working with the turtle module as a way of learning the language.
Thanks to stackoverflow, I researched and learned how to copy the image into an encapsulated postscript file and it works great. There is one problem, however. The turtle module allows background color which shows on the screen but does not show in the .eps file. All other colors, i.e. pen color and turtle color, make it through but not the background color.
As a matter of interest, I do not believe the import of Tkinter is necessary since I do not believe I am using any of the Tkinter module here. I included it as a part of trying to diagnose the problem. I had also used bgcolor=Orange rather than the s.bgcolor="orange".
No Joy.
I am including a simple code example:
# Python 2.7.3 on a Mac
import turtle
from Tkinter import *
s=turtle.Screen()
s.bgcolor("orange")
bob = turtle.Turtle()
bob.circle(250)
ts=bob.getscreen()
ts.getcanvas().postscript(file = "turtle.eps")
I tried to post the images of the screen and the .eps file but stackoverflow will not allow me to do so as a new user. Some sort of spam prevention. Simple enough to visualize though, screen has background color of orange and the eps file is white.
I would appreciate any ideas.
Postscript was designed for making marks on some medium like paper or film, not raster graphics. As such it doesn't have a background color per se that can be set to given color because that would normally be the color of the paper or unexposed film being used.
In order to simulate this you need to draw a rectangle the size of the canvas and fill it with the color you want as the background. I didn't see anything in the turtle module to query the canvas object returned by getcanvas() and the only alternative I can think of is to read the turtle.cfg file if there is one, or just hardcode the default 300x400 size. You might be able to look at the source and figure out where the dimensions of the current canvas are stored and access them directly.
Update:
I was just playing around in the Python console with the turtle module and discovered that what the canvas getcanvas() returns has a private attribute called _canvas which is a <Tkinter.Canvas instance>. This object has winfo_width() and winfo_height() methods which seem to contain the dimensions of the current turtle graphics window. So I would try drawing a filled rectangle of that size and see if that gives you what you want.
Update 2:
Here's code showing how to do what I suggested. Note: The background must be drawn before any other graphics are because otherwise the solid filled background rectangle created will cover up everything else on the screen.
Also, the added draw_background() function makes an effort to save and later restore the graphics state to what it was. This may not be necessary depending on your exact usage case.
import turtle
def draw_background(a_turtle):
""" Draw a background rectangle. """
ts = a_turtle.getscreen()
canvas = ts.getcanvas()
height = ts.getcanvas()._canvas.winfo_height()
width = ts.getcanvas()._canvas.winfo_width()
turtleheading = a_turtle.heading()
turtlespeed = a_turtle.speed()
penposn = a_turtle.position()
penstate = a_turtle.pen()
a_turtle.penup()
a_turtle.speed(0) # fastest
a_turtle.goto(-width/2-2, -height/2+3)
a_turtle.fillcolor(turtle.Screen().bgcolor())
a_turtle.begin_fill()
a_turtle.setheading(0)
a_turtle.forward(width)
a_turtle.setheading(90)
a_turtle.forward(height)
a_turtle.setheading(180)
a_turtle.forward(width)
a_turtle.setheading(270)
a_turtle.forward(height)
a_turtle.end_fill()
a_turtle.penup()
a_turtle.setposition(*penposn)
a_turtle.pen(penstate)
a_turtle.setheading(turtleheading)
a_turtle.speed(turtlespeed)
s = turtle.Screen()
s.bgcolor("orange")
bob = turtle.Turtle()
draw_background(bob)
ts = bob.getscreen()
canvas = ts.getcanvas()
bob.circle(250)
canvas.postscript(file="turtle.eps")
s.exitonclick() # optional
And here's the actual output produced (rendered onscreen via Photoshop):
I haven't found a way to get the canvas background colour on the generated (Encapsulated) PostScript file (I suspect it isn't possible). You can however fill your circle with a colour, and then use Canvas.postscript(colormode='color') as suggested by #mgilson:
import turtle
bob = turtle.Turtle()
bob.fillcolor('orange')
bob.begin_fill()
bob.circle(250)
bob.begin_fill()
ts = bob.getscreen()
ts.getcanvas().postscript(file='turtle.eps', colormode='color')
Improving #martineau's code after a decade
import turtle as t
Screen=t.Screen()
Canvas=Screen.getcanvas()
Width, Height = Canvas.winfo_width(), Canvas.winfo_height()
HalfWidth, HalfHeight = Width//2, Height//2
Background = t.Turtle()
Background.ht()
Background.speed(0)
def BackgroundColour(Colour:str="white"):
Background.clear() # Prevents accumulation of layers
Background.penup()
Background.goto(-HalfWidth,-HalfHeight)
Background.color(Colour)
Background.begin_fill()
Background.goto(HalfWidth,-HalfHeight)
Background.goto(HalfWidth,HalfHeight)
Background.goto(-HalfWidth,HalfHeight)
Background.goto(-HalfWidth,-HalfHeight)
Background.end_fill()
Background.penup()
Background.home()
BackgroundColour("orange")
Bob=t.Turtle()
Bob.circle(250)
Canvas.postscript(file="turtle.eps")
This depends on what a person is trying to accomplish but generally, having the option to select which turtle to use to draw your background to me is unnecessary and can overcomplicate things so what one can do instead is have one specific turtle (which I named Background) to just update the background when desired.
Plus, rather than directing the turtle object via magnitude and direction with setheading() and forward(), its cleaner (and maybe faster) to simply give the direct coordinates of where the turtle should go.
Also for any newcomers: Keeping all of the constants like Canvas, Width, and Height outside the BackgroundColour() function speeds up your code since your computer doesn't have to recalculate or refetch any values every time the function is called.