Currently have a program where a user is able to draw their own shape using mouse clicks. It then takes a list of QPointFs (obtainted from user mouse clicks) and creates a QPolygonF. This step is fine and a visible outline of the polygon can be seen when converted to a PolygonItem and added to a graphics view. However I need to convert it to a QImage and set its pixels to green (colour important later when solving the centre of mass) but I'm unsure how to do so. Currently I have...
self.poly=QPolygonF(self.vertexList) #works
self.polyItem=QGraphicsPolygonItem(self.poly) #works, visible when added to scene
self.pixItem=QGraphicsPixmapItem(self.polyItem) #for some reason this step doesn't work. The pixmap item is created, however its empty
self.addItem(self.pixItem) #not visible, this is where it goes wrong
self.pix = self.pixItem.pixmap()
self.image=self.pix.toImage()
self.image.convertToFormat(4)#4=RGB32
value=qRgb(0,255,0) #These last two lines turn it green but irrelevant to issue
self.image.fill(value)
As far as I understand you can convert one type of item to another (no error is given) but with the polygon item to pixmap item it goes blank. Would be grateful for any help.
Related
I want to find the exact coordinates of the following parts of widgets as shown in the image in blue circles. I cannot figure out how to do this I have tried the following:
self.winfo_x()
self.winfo_y()
self.winfo_xy()
All of these will not give the answer and I do not know any other ways after any of my research. I am making a custom way to drag widgets and I am creating a containment system and need the beginning and end points.
Image(I could not show, I don't have the reputation needed):https://i.stack.imgur.com/ID3kX.png
EDIT:
Here is the picture of my code, I implemented the answer below by using hypothetical button called s:
https://i.stack.imgur.com/mnIaf.png
You can use the method winfo_x to get the x coordinate of the window relative to its parent. You can use winfo.parent to get the name of the parent window, and the method nametowidget to convert that to a widget. The solution is to combine those to recursively get the x or y coordinate of the widget and every parent.
It might look something like this:
def absolute_x(widget):
if widget == widget.winfo_toplevel():
# top of the widget hierarchy for this window
return 0
return widget.winfo_x() + absolute_x(widget.nametowidget(widget.winfo_parent()))
I'm new to tkiinter and i didn't manage to find a solution to my problem on internet.
First thing I need to draw a sort of table with triangles similar to the one in this picture (https://www.tilelook.com/system/tile_picture/resource/4973584/d3d_default_RE04MC017.png).
Then the user can choose a color somewhere (from a list or something similar) and change the color of a triangle by clicking on it. The most important thing is that i need to retrieve these information in the code (for each trinagle I need to know which color the user choosed).
Edit:
I still didn't write any code, but i know how to draw the table with Canvas and more or less how to handle the coloring part. The hard part for me is how to retrieve the informations in the code, I think it's like considering each element of the table like an independent object or something like that, but i have no idea how to do it.
I won't give you a complete solution but you may find the below a helpful starting point
import tkinter as tk
from random import choice
def getRandomColor():
return choice(['red','blue','green','yellow','white','goldenrod'])
def click(event):
print(vars(event))
item = event.widget.find_withtag('current')
event.widget.itemconfig(item,fill=getRandomColor())
root = tk.Tk()
root.grid()
c = tk.Canvas(root,width=300,height=300,bg='black')
c.grid()
c.create_polygon(0,0,100,0,50,100,fill='blue',tag='tri_1')
c.create_polygon(100,0,50,100,150,100,fill='yellow',tag='tri_2')
c.bind('<Button-1>',click)
root.mainloop()
This will create two triangles. If you click on a triangle it will change to a random color (from a small list of colors).
This will give you some ideas about
a. drawing polygons on a tkinter canvas
b. binding a function to a click
c. changing the properties of a canvas item
Hope you find this helpful
I am making a game, with pygame, and i want it to be that when the mouse hovers over my text, the box gets shaded.
here is what I have so far:
in the event-handling loop:
(tuples in CheckToUnshadeBoxes are pairs of text-surfaces and their boxes (from get_rect method))
elif event.type == MOUSEMOTION:
CheckToShadeBoxes(event, LERect, LoadRect, PlayRect)
CheckToUnshadeBoxes(event, (LERect, LESurf),
(LoadRect, LoadSurf), (PlayRect, PlaySurf))
here is CheckToShadeBoxes:
def CheckToShadeBoxes(event, *args):
'''
shade the box the mouse is over
'''
for rect in args:
s = pg.Surface((rect.width, rect.height))
s.set_alpha(50)
print(rect.x, rect.y)
s.fill(COLOURS['gray'])
x, y = event.pos
if rect.collidepoint(x, y):
SURFACE.blit(s, (rect.x, rect.y))
and CheckToUnshadeBoxes:
def CheckToUnshadeBoxes(event, *args):
''' if the mouse moves out of the box, the box will become unshaded.'''
for (rect, TextSurf) in args:
x, y = event.pos
if not rect.collidepoint(x, y):
SURFACE.blit(TextSurf, (rect.x, rect.y))
This works fine! except that when I move the mouse inside of the box, the box will continue to get darker and darker until you cant even see the text! I know it is a small detail, but it has been bugging me for a long time and I don't know how to fix it.
by the way, if it is not evident enough, COLOURS is a dictionary with string keys and RGB tuple values, and SURFACE is my main drawing surface.
If you have any questions about my code, or anything I have done just comment!
If the rects you are passing are your own derived class, then I recommend making a .is_shaded class variable and checking to make sure the variable is false before shading it.
If these rects aren't your own class extending another, then I recommend you make one, as it would make it much simpler
The problem with your code is that you keep adding in dark rectangles when the mouse is hovered over. No wonder it gets darker and darker.
All that is needed is for your code to be shuffled around a little.
Inside your event handling, you should call a function to check if it should shade the text. This should return a Boolean value. Store this in a variable. Most of the code from the CheckToShadeBoxes function will do the trick.
In your render section, you should render just one surface on top of your text, based on whether the Boolean value is true or not. The code that creates a gray surface in the CheckToShadeBoxes function will work but make sure it is only one surface. Don't create a new surface in every iteration. Define it outside once and blit it to the screen inside the loop.
This should fix your problem!
I hope this answer helps you! If you have any further questions please feel free to post a comment below!
Simple question, but I've tried a few things and nothing seems to work.
I want to overlay some statistics onto a 3d VTK scene, using 2D vtkTextActors. This works fine, but the text is at times difficult to see, depending on what appears behind it in the 3D scene.
For this reason, I'd like to add a 2d, semi-transparent "box" behind my text actors to provide a darker background.
Which VTK object is appropriate for this? I've tried so far:
vtkLegendBoxActor: Not what I want, but I can use this with no text to display a semi-transparent box on screen. I cannot size it directly and I get warnings about not initialising some of the content.
vtkImageData: Tried manually creating image data and adding it to the scene; I believe it was placed within the 3d scene and not used as an overlay. If that's not the case then I couldn't get it to show at all.
vtkCornerAnnotation: Scales with window size, is fixed to a corner and the background opacity cannot be set AFAIK.
vtkTextActor: Cannot set a background color or opacity
Can anyone tell me how they might achieve what I'm after in VTK?
I've found a way to do this with vtkPolyMapper2D which seems to work okay. It seems to be a very stupid way to do this. If there is something more elegant, I'm all ears.
import vtk
extents = [[0,0],[620,0],[620,220],[0,220]]
polyPoints = vtk.vtkPoints()
for x, y in extents:
polyPoints.InsertNextPoint(x, y, 0)
num_corners = len(extents)
polyCells = vtk.vtkCellArray()
polyCells.InsertNextCell(num_corners + 1)
for i in range(0, num_corners):
polyCells.InsertCellPoint(i)
polyCells.InsertCellPoint(0) ## Rejoin at the end
poly_profile = vtk.vtkPolyData()
poly_profile.SetPoints(polyPoints)
poly_profile.SetPolys(polyCells) ## Goes solid
cut_triangles = vtk.vtkTriangleFilter()
cut_triangles.SetInput(poly_profile)
_poly_mapper = vtk.vtkPolyDataMapper2D()
_poly_mapper.SetInput(poly_profile)
_poly_mapper.SetInputConnection(cut_triangles.GetOutputPort())
_actor = vtk.vtkActor2D()
_actor.SetMapper(_poly_mapper)
_actor.GetProperty().SetColor([0.1,0.1,0.1])
_actor.GetProperty().SetOpacity(0.5)
#Add to renderer as normal
just use vtktexture, vtkimagedata & add your own image as texture background to the vtkrenderer by reducing the opacity like a watermark. thats it
I'm trying to simulate an American traffic light, with 3 circles on a rectangle, all drawn on a set Canvas. The simulation is supposed to mirror "animation" by changing which light is displayed every 2 seconds in the following order: green > yellow > red > green, etc forever.
The only way I can think of to do this is by using a canvas.move(), canvas.after(), canvas.update() pattern to move a filled oval object to superimpose one unfilled circle at a time. I've gotten the logic down to move a circle at the proper speed and in the correct order. The thing is, I just instantiate a circle filled with "green", but I can't change it to be "yellow" or "red" using this method. It seems silly to have to canvas.delete("filled") and redraw it in a new place with a different fill every 2 seconds, because that's a lot to do for such a simple program.
Question 1: Is there a way I can just alter the fill option for my filled Canvas object at will, using some method or other means?
Question 2: Am I approaching this scenario incorrectly? Is there a better way to simulate this?
Yes you should be able to change settings of the canvas with config().
Likewise, use itemconfig() to change items on the canvas. This does require that you save a handle to the item or tag them.
Example based on tkinterbook:
item = canvas.create_line(xy, fill="red")
canvas.coords(item, new_xy) # change coordinates
canvas.itemconfig(item, fill="blue") # change color