I created a canvas and specified the height using (width, height), but when it comes to the GUI, it doesn't change the size at all.
atEdit=Frame(Attend,borderwidth=0)
atEdit.grid(row=2,column=0,columnspan=5,sticky='news',pady=(0,10),padx=10)
scrollbar = Scrollbar(atEdit)
scrollbar.grid(row=0,column=5,sticky='ns')
canvas = Canvas(atEdit,bg='black',height=20)
canvas.grid(row=0,column=0,columnspan=5,sticky='news')
scrollbar.config(command = canvas.yview)
left = Frame(canvas,borderwidth=0,bg='#dbdbdb',height=2)
left.grid(row=0,column=0,sticky='news')
right=Frame(canvas,borderwidth=0,bg='white',height=2)
right.grid(row=0,column=1,columnspan=4,sticky='news')
left.bind('<Configure>',lambda event,canvas=canvas:self.onFrameConfigure(canvas))
right.bind('<Configure>',lambda event,canvas=canvas:self.onFrameConfigure(canvas))
I add labels to the 'left' and 'right', which increases the size of the frames, but it shouldn't grow larger than the specified size. Is there anyway to make the canvas a fixed size, even if I add more labels to it, and be able to scroll through it using the scrollbar?
def onFrameConfigure(self,canvas):
canvas.configure(scrollregion=canvas.bbox("all"))
Related
I am trying to make an application for a school project, one of the features is a messaging service where users can message each other, this is accessed via a button in which the messaging GUI is loaded. I have already added a canvas as the background for the main GUI at the start of the program but for the message interface I have added another canvas which overlaps and will be using a scrollbar to scroll through the messages and display them.
In essence my problem is that I would like to position another canvas on top of the main canvas using co-ordinates and add a scrollbar which only fits to the right hand side of this smaller canvas.
Thanks in advance :)
I have tried to add a scrollbar to it using pack(), grid(), place() and canvas.create_window() however in all instances the scrollbar either does not appear, does not fill the entire right hand side of the second canvas, or is not placed in the correct position. The closest I got was with the place() function where I have managed to position the scrollbar and canvas using "relx", "rely" and "relheight" however the scrollbar is not scrolling the canvas.
root = Tk() #creates the GUI
root.title("Eclass")
root.iconbitmap(default='icon.ico') #sets icon
root.state('zoomed')
backgroundcolour = root.cget("bg")
screen_width = root.winfo_screenwidth() - 15
screen_height = root.winfo_screenheight()
canvas = Canvas(root, width = screen_width, height = screen_height)
def messaging():
canvas.delete("all")
msg_canvas = Canvas(canvas, width = 1530, height = 730, bg = "red")
#canvas.create_window(1123,600, window = msg_canvas) this is where I tried to add the second canvas using the create_Window function
msg_canvas.place(relx=0.186, rely=0.227)
msg_scrollbar = Scrollbar(canvas, orient="vertical",command=msg_canvas.yview)
msg_scrollbar.place(relx=0.975,rely=0.2295, relheight = 0.717)
msg_canvas.config(scrollregion=msg_canvas.bbox(ALL))
I expect the canvas to be placed within the current co-ordinates given via relx and rely or in previous trial the co-ordinates in canvas.create_window(), I then expect the msg_scrollbar to be on the right hand side of msg_canvas and fill to its Y (the height of the scrollbar should be the same as the height of the canvas). In actuality the canvas and scrollbar are in the correct co-ordinates however the scrollbar does not scroll the msg_canvas even after moving it.
, In essence, my problem is that I would like to position another canvas on top of the main canvas using co-ordinates and add a scrollbar which only fits the right-hand side of this smaller canvas.
I recommend against using place. Both pack and grid are better for creating code that is responsive to changes in resolution, window size, and fonts.
IMHO, the simplest solution is to use pack to put the main canvas at the bottom, then in the remaining space put the scrollbar on the right and the secondary canvas on the left. Note: the order is important, as each time you call pack it will use up all of the space on the given side, reducing the space available to future widgets.
canvas.pack(side="bottom", fill="both", expand=True)
msg_scrollbar.pack(side="right", fill="y")
msg_canvas.pack(side="left", fill="both", expand=True)
You can accomplish the same thing with grid, but it requires additional lines of code to configure row and column weights. With grid order isn't as important since you are explicitly setting rows and columns.
msg_canvas.grid(row=0, column=0, sticky="nsew")
msg_scrollbar.grid(row=0, column=1, sticky="ns")
canvas.grid(row=1, column=0, columnspan=2, sticky="nsew")
root.grid_rowconfigure((0,1), weight=1)
root.grid_columnconfigure(0, weight=1)
in my vaadin project i have a vertical layout (with the height 100%), with two other vertical layouts inside. the fist one has a fixed height, while the second one should fill the remaining space of the browser-window. it will have a bigger height than the remaining space and has an overflow-y: scroll css-attribute. i tried this with the method setExpandRatio but did not work (the height was often more than the remaining space). can i achieve this just with vaadin, or do i have to use javascript for this?
AbstractOrderedLayout root = new VerticalLayout();
root.setHeight(100, Unit.PERCENTAGE);
AbstractOrderedLayout child1 = new VerticalLayout();
AbstractOrderedLayout child2 = new VerticalLayout();
child1.setHeight(200, Unit.PIXELS);
root.addComponent(child1);
child2.setHeightUndefined();
root.addComponent(child2); // child2 will be filled with items. if its higher than the remaining space, it should be scrollable (overflow-y: auto)
// root.setExpandRatio(child2, 1F);
So if i've understood right you would like to have a first area with fixed height and a second area that could be bigger than remaining height so it needs to scroll.
If that's the case, here's the layout
VerticalLayout"Main" (sizeFull)
VerticalLayout"1" (width 100%, height fixed): fill this layout with your fixed height content
Panel (sizeFull + setExpandRation on VerticalLayoutMain to 1)
VerticalLayout"2" (width100%, heightUndefined): fill this layout with your other content
Regards
I have a project where i have to create a 4 way split screen using pygame. On this screen i have to draw the same image on each of the screen just have different view of the image. I just can not figure out how to create this 4 way split screen using pygame.
I need my screen to be divided like above so i can draw my points onto each section.
I have been looking around and I can not find anything like this so any help would be great
thanks
In addition to the surface you have that gets rendered to the display, likely called something like screen, you should create another surface which all of the "action" gets drawn to. You can then use a Rect object for each quadrant of the screen which will represent the "camera" (assuming each quadrant doesn't necessarily need to show exactly the same image). When you draw back to screen, you use each camera Rect object to select a portion of the game space to draw to a specific quadrant.
# canvas will be a surface that captures the entirety of the "action"
canvas = pygame.Surface((800, 600))
# the following are your "camera" objects
# right now they are taking up discrete and even portions of the canvas,
# but the idea is that they can move and possibly cover overlapping sections
# of the canvas
p1_camera = pygame.Rect(0,0,400,300)
p2_camera = pygame.Rect(400,0,400,300)
p3_camera = pygame.Rect(0,300,400,300)
p4_camera = pygame.Rect(400,300,400,300)
On each update, you would then use these "camera" objects to blit various portions of the canvas back to the screen surface.
# draw player 1's view to the top left corner
screen.blit(canvas, (0,0), p1_camera)
# player 2's view is in the top right corner
screen.blit(canvas, (400, 0), p2_camera)
# player 3's view is in the bottom left corner
screen.blit(canvas, (0, 300), p3_camera)
# player 4's view is in the bottom right corner
screen.blit(canvas, (400, 300), p4_camera)
# then you update the display
# this can be done with either display.flip() or display.update(), the
# uses of each are beyond this question
display.flip()
There is no functions to split screen. But you can draw 4 views directly on screen or you can draw on 4 surfaces (pygame.Surface) and than blit surfaces on screen.
Since you were looking for a way to split the screen in to 4 sections and draw some points on to them I'd suggest creating 4 subsurface surfaces of the original "canvas" image for convenience.
These surfaces would act as your player(split screen) canvasses which can easily be modified.
This will enable the usage of normalized coordinates for player specific drawing purposes.
Assuming you have a screen surface set up
# Image(Surface) which will be refrenced
canvas = pygame.Surface((800, 600))
# Camera rectangles for sections of the canvas
p1_camera = pygame.Rect(0,0,400,300)
p2_camera = pygame.Rect(400,0,400,300)
p3_camera = pygame.Rect(0,300,400,300)
p4_camera = pygame.Rect(400,300,400,300)
# subsurfaces of canvas
# Note that subx needs refreshing when px_camera changes.
sub1 = canvas.subsurface(p1_camera)
sub2 = canvas.subsurface(p2_camera)
sub3 = canvas.subsurface(p3_camera)
sub4 = canvas.subsurface(p4_camera)
Now drawing on any of of the subsurfaces with these normalized coordinates
# Drawing a line on each split "screen"
pygame.draw.line(sub2, (255,255,255), (0,0), (0,300), 10)
pygame.draw.line(sub4, (255,255,255), (0,0), (0,300), 10)
pygame.draw.line(sub3, (255,255,255), (0,0), (400,0), 10)
pygame.draw.line(sub4, (255,255,255), (0,0), (400,0), 10)
# draw player 1's view to the top left corner
screen.blit(sub1, (0,0))
# player 2's view is in the top right corner
screen.blit(sub2, (400, 0))
# player 3's view is in the bottom left corner
screen.blit(sub3, (0, 300))
# player 4's view is in the bottom right corner
screen.blit(sub4, (400, 300))
# Update the screen
pygame.display.update()
Note that modifications to the subsurface pixels will affect the canvas as well. I'd recommend reading the full documentation on subsurfaces.
When taking a screenshot of my scene in JavaFx, I save the BufferedImage to a file as a PNG/JPG. When I try to maximize the image size to its full length, I get Black borders on the picture from the left of the image to the bottom without the image increasing its size at all.
The size of the image only increases until I set my dimensions to 1300x700 as shown below.
BufferedImage image = new BufferedImage(1300, 700, BufferedImage.TYPE_INT_RGB);
However once I increase the dimensions greater than 1300x700, the black borders appear.
The following picture is set to
BufferedImage image = new BufferedImage(1500, 900, BufferedImage.TYPE_INT_RGB);
As you can see, part of the image is still cut off and there is now a big black border next to the image rather than the actual full sized image.
The following picture is set to
BufferedImage image = new BufferedImage(1300, 700, BufferedImage.TYPE_INT_RGB);
As you can see, the image is still cut off at the same spot as before but there is no black border along side with it.
How can I fit the whole snapshot of my current scene into one file without these borders and without any of the content getting cut off?
Here is my code:
File fa = new File("test.jpg");
snapshot = quotes.getScene().snapshot(null);
RenderedImage renderedImage = SwingFXUtils.fromFXImage(snapshot, null);
BufferedImage image = new BufferedImage(1300, 700, BufferedImage.TYPE_INT_RGB);
image.setData(renderedImage.getData());
ImageIO.write(image, "jpg", fa);
The black border comes from uninitialized pixel buffer, inside your BufferedImage object.
So, I guess the renderedImage itself does not contains the right part of your scene.
The scene may not yet be properly resized when you are taking the snapshot. Try to give an appropriate WritableImage to the snapshot method:
snapshot = quotes.getScene().snapshot(new WritableImage(1500, 900));
I have a zoomable QGraphicsView with scene that contains hundreds (and even thousands) of datapoints. The points are represented by QGraphicsEllipseItems and collected into a QGraphicsItemGroup. When the view is zoomed in to I want datapoints to stay at a constant size (i.e., the distances between neigbouring points increase but the sizes stay the same). Right now I achieve this by running this code every time the user zooms in:
#get all the QGraphicsEllipseItems that make up the QGraphicsItemGroup
children = graphics_item_group.childItems()
for c in children:
#base_size_x and base_size_y are the sizes of the
#untrasformed ellipse (on the scene) when zoom factor is 1
#New width and height are obtained from the original sizes and
#the new zoom factors (h_scale, v_scale)
new_width = base_size_x/h_scale
new_height = base_size_y/v_scale
#The top-left corner of the new rectangle for the item has to be recalculated
#when scaling in order to keep the center at a constant position
#For this, the center of the item has to be stored first
old_center_x = c.rect().center().x()
old_center_y = c.rect().center().y()
#New coordinates of the rectangle top left point are calculated
new_topleft_x = old_center_x - new_width/2.
new_topleft_y = old_center_y - new_height/2.
#Finally a new rectangle is set for the ellipse
c.setRect(new_topleft_x, new_topleft_y, new_width, new_height)
This code works. The problem is that it is quite slow (without the compensatory scaling zooming in/out works very smoothly). I tried turning off antialiasing for the view but it makes things look pretty ugly. Is there anything else that I can do to make the processing/redrawing faster?
In the constructor of the QGraphicsItem:
setFlag(ItemIgnoresTransformations);
When you zoom, the item will remain the same size, and you won't have to manually scale it.