BACKGROUND:
I have a python program that is being used by a number of engineers. It indicates the status of some piece of equipment under test.
I am using a QScrollArea() to contain a QGridLayout which is packed with alot of information.
bit_grid = QtGui.QGridLayout()
...
scroll = QtGui.QScrollArea()
info = QtGui.QWidget()
info.setLayout(bit_grid)
scroll.setWidget(info)
There are quite a few status indicators on the GUI and as such the scrollbar is used to ensure the GUI fits on one screen.
When an engineer want's to describe a failure what they are doing right now is taking multiple screenshot, one for each new displayed area of the ScrollArea. They are then stitched together to make one large image.
Is there a way to generate a png (or an img format) of the area that could be display within a ScrollArea?
Try this:
pixmap = QtGui.QPixmap.grabWidget(scroll)
pixmap.save('path/to/file.png', None, 100)
This snippet will take a snapshot of whatever is inside the scrollArea and save that as a png image to path/to/ folder as file.png
ok solved.
widget = self.scroll.widget()
pixmap = QtGui.QPixmap(widget.size())
widget.render(pixmap)
pixmap.save(filename, 'PNG', 100)
The key was to grab the widget that is in scroll as this could then be (virtually) rendered. The resultant pixmap could then be saved.
Related
I'm having a bit of a problem: I'm trying to access the width of a container in which I've added a sprite to, but it seems to return as 1. However, when I inspect the object in the console, it gives me the proper width.
I wrote up a code pen showing the issue, but it goes something like this:
var container = new PIXI.Container();
app.stage.addChild(container);
var sprite = PIXI.Sprite.fromImage('https://i2.wp.com/techshard.com/wp-
content/uploads/2017/05/pay-1036469_1920.jpg?ssl=1&w=200');
container.addChild(sprite);
console.log(container.height);
console.log(container);
The first console log returns 1, while if I go into the object in the second log it gives me 141.
I'm trying to center the container like in the demo. The demo container returns the proper width, unless you try and do it for only one "bunny" (replacing bunny texture with internet image, also the for loop is commented out).
Any suggestions on a proper approach for this?
Cheers
There's a few things to address here.
Firstly, what the problem in your codepen is:
You're creating a texture from an image that has yet to be loaded.
Until the image loads pixi will not be able to give you the dimensions of it, and the container reports a width and height of 1 when you immediately query them. If you put the same console.log statement in a timeout then it will report the dimensions after the image has loaded and thus the dimensions will be accurate.
Logging out the object itself seems to work because when you examine the contents of it they've been updated to the correct values because the image has loaded by that point.
If the texture is already in the cache at the point that you create a new sprite using it then you won't have to wait before you can access its true dimensions.
Secondly, why the bunny example on pixi's site doesn't have the same problem:
Actually, it does. You just don't notice it.
The magic is in the bunny.anchor.set(0.5);. It lines 25 sprites with width and height of 1 out in a grid. By spacing them out, their container now has width and height of 160.
This container is now centered immediately based on its current dimensions, and then when the sprite textures finish loading and the sprites are updated with their new dimensions. Due to their anchor being set to 0.5, however, this means they remain centered despite their container now being larger.
You can play around with using a larger image than the bunny to exaggerate things and changing the anchor value, along with using the rerun code button rather than just refreshing the page. If you rerun the code the image being used for the texture remains cached by pixi so you get different results.
Lastly, how you would resolve this issue:
Loading your assets before creating sprites with them.
(Or at least waiting before they're loaded before querying their dimensions to position things)
You can find an example of the resource loader that pixi has here: http://pixijs.io/examples/?v=next-interaction#/basics/spritesheet.js
Need to place buttons on image but image always stays on center and buttons stays on sides.
Why not place an image on a button instead? It's much easier :)
getting the buttons to have an image can be kind of tricky (you kind of need a 2 layered approach), but changing the image is easy.
x_image = 'x.png'
o_image = 'o.png'
then...
x_image_for_button = PhotoImage(file=x_image)
o_image_for_button = PhotoImage(file=o_image)
then.....
button = tk.Button(self.controller, image=o_image_for_button, command=lambda: command_or_something)
button.config(width="40", height="40")
button.place(x=5, y=5)
(add in self. or root. etc)
now all you do to change the image is:
button.set(image=o_image_for_button)
#on second thought... maybe use `button.config(image=o_image_for_button)` insted
easy :)
I am now studying an online pygame tutorial. However, I am not sure how it works when trying to place text on the screen. According to the official docs for pygame.font.Sysfont():
Return a new Font object that is loaded from the system fonts. The font will match the requested bold and italic flags. If a suitable system font is not found this will fall back on loading the default pygame font. The font name can be a comma separated list of font names to look for.
What is a font?
font = pygame.font.SysFont(None, 25)
# message to the user
def message_to_screen(msg,color):
screen_text = font.render(msg, True, color)
screen.blit(screen_text, [screen_width/2,screen_height/2])
Ok, here is the simplest explanation i can give you:
Modules such as Pygame are simple (or sometimes not that simple...) codes that add new features and functions to your normal built in python functions. This means that when you import a module you also inherent from that module all of its functions and classes. So for example, the normal python does not contain the function "draw"
pygame.draw.rect(arguments)
however when you import pygame, you inherent that function from the pygame code. allowing you to draw and develop a GUI for better programs.
Same is with objects. Python is an 'object orientated programming language". Objects are a type of data store that defines and structures your code. So for example, sprites in Pygame can be anything you want. Your sprite can be anything you want from a monkey, or a freaking mummy eating zombie, to a simple rectangle. To create the exact sprite you want with the right shape, color, rect, and image, you need to structure it with a class. A class is what will create the object for your sprite. Look at this here:
#Here is the class named 'Button' of type ' pygame.sprite.Sprite'
class Button(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
#Here we define the shape of the sprite. In the case it is a simple
#150 by 75 rectangle surface. The shape can also be an image or any
#or any geometric shape you want
self.image = pygame.Surface((150, 75))
#here we define the color of the sprite
self.image.fill(green)
#and here we make sure the sprite has a rect
self.rect = self.image.get_rect()
so as you see this class defines all what we need to create this simple sprite. Of course it can have many more variables to it depending on what the sprite is, but lets stick with something simple for now
Now the class stores this information in an object, to be used later. Like this:
MySpriteObject = Button()
simple enough i would say. so now you have a sprite object and can use pygames' many function to draw it on the screen, add interaction to it, group it, and a lot of other things.
so Finally you understand the idea of an object in python. Now to you're actual question.
What is a font?
Well a font is an object that you get when you import pygame. You don't have to do the class stuff at the top as the pygame module does that for you. Just create the object and use the function 'render'. So essentially it is an object that you can change two things in as you like. the font, and the size
MyFontObject = pygame.font.Font(#Font here, #size here)
If you make the Font argument None, then it will give you the default pygame font. Thats what I usually do. However, if you want to change the font, you can either download a font (usually a .ttf) and then type in its folder path in the Font argument, or you can use a font that you have on your computer. To do that instead of
MyFontObject = pygame.font.Font(#Font here,#size here)
you use
MyFontObject = pygame.font.SysFont(#Name of font here, #size here)
Where #Name of font here is, you can replace it by any font installed on your computer. To get a list of the names of fonts on your computer that pygame can identify:
pygame.font.get_fonts()
Ok, so that is how you create the font object. Now to rendering it.
Rendering the font uses the font object to change the shape and color of the text you want to display. Here is how its done
text = MyFontObject.render(#Your Text Here,#true or false,#color)
screen.blit(tex,t(#X axis,#Y axis))
Pretty self explanatory. Except for the #true or false i guess. That pretty much asks you if you want to use a technique that helps the text look less pixeled and square-like. If you provide true it will. If you dont the text will look awefull, so always keep it true.
So that's pretty much what i have to say. Here is a short summary:
1.) An object is a type of data store which stores different variables to structure and define your code. So therefore a font object is an object that defines the different things for a font, such as size and font type
2.) to create an object we use a class as shown above
3.) A font class is already there with the pygame module so you just have to call the font object straight away:
MyFontObject = pygame.font.Font(#filepath or None for the default pygame font,#size here)
or for a font that is installed on your system such as ariel (which can all be viewed with pygame.font.get_font())
MyFontObject = pygame.font.SysFont(#Name of system font here,#size here)
4.) To put this font object to use you render it:
text = MyFontObject.render(#Text here,#True or false,#color of text)
then normally blit it on the screen and call pygame.display.update
screen.blit(text,(#X axis,#Y axis)
pygame.display.update()
I hope this helps. I know I'm not the best explainer and I write too much, but you should read the summary at least.
P.S: Sorry for using sprites to explain classes and objects. I know I went of topic but it was just an example.
I have a QLabel which displays an image. Currently, I have the image set to keep it's aspect ratio, and grow as big as it can within the QLabel.
Is there any way I can also set the QLabel to maintain the image's aspect ratio? I do not want to have "blank" QLabel space either side of the image when the label is wider than the image.
I have been looking for any sort of QLabel property that would allow me to set the aspect ratio of the label, but have not managed to get anything to do what I wanted to do.
All the answers I have seen relate to keeping the aspect ratio of a resized QPixmap image, but not of the QLabel containing it.
Any help would be great!
Cheers
FP
I seem to have cracked it, so incase anyone else was wondering how to do this:
I took tmoreau's solution and modified it slightly. For it to work, you need to set the QLabel's maximum size to the image's new size prior to the paint event. Immediately afterwards, you need to set the maximum size for the QLabel to something very large, otherwise, you will not be able to enlarge the image at all as you will have specified the maximum size to be that of the current image.
def paintEvent(self, event):
size = self.size()
painter = QtGui.QPainter(self)
point = QtCore.QPoint(0,0)
scaledPix = self.pixmap.scaled(size, Qt.KeepAspectRatio, transformMode = Qt.SmoothTransformation)
self.setMaximumSize(scaledPix.size())
point.setX(0)
point.setY(0)
#print (point.x(), ' ', point.y())
painter.drawPixmap(point, scaledPix)
self.setMaximumSize(QtCore.QSize(4000,5000))
If anyone has a better solution, by all means please let me know!
I want to add image and some text on another image and create a single image. I have got to add text but not able to figure out that how to add image. Any help?
This snippet assumes you have UIImage's named bottomImage for the base image to be drawn upon, and topImage that will be drawn ON (above) the bottomImage. xpos,ypos are floats to describe the target x,y (top left) position where topImage will be drawn, and targetSize the size in which topImage will be drawn on bottomImage.
...
UIGraphicsBeginImageContext( bottomImage.size );//create a new image context to draw offscreen
[bottomImage drawInRect:CGRectMake(0,0,bottomImage.size.width,bottomImage.size.height)];//draw bottom image first, at original size
[topImage drawInRect:CGRectMake(xpos,ypos,targetSize.width,targetSize.height) blendMode:kCGBlendModeNormal alpha:1];//draw the image to be overlayed second, at wanted location and size
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();//get newly drawn image context into a UIImage
UIGraphicsEndImageContext();//stop drawing to the context
return newImage;//return/use the newly created image
This is not thread safe - creating a UIImage in a thread is not recommended.