I need to draw a rectangle in a tkinter.canvas to respond click event:
click_area = self.canvas.create_rectangle(0,0,pa_width,pa_height,fill='LightBlue',outline='lightBlue',tags=['A','CLICK_AREA'])
self.canvas.tag_bind('CLICK_AREA','<Button>',self.onClickArea)
it works.
at this moment, I have to draw a series of grid on the canvas, and I want them to be covered with the click_area, so that I need to make the click_area transparent.
but, when I wrote like this:
click_area = self.canvas.create_rectangle(0,0,pa_width,pa_height,fill='',outline='lightBlue',tags=['A','CLICK_AREA'])
it did not respond to click any longer.
So, my question is how to make it transparent and keep it responding to click. Or, is there any other way to implement what I want.
Thank you very much.
I came across this same issue trying to use the find_closest Canvas method to modify existing rectangles, but simply binding to the canvas didn't work. The issue is that a Tkinter rectangle without a fill will only respond to clicks on its border.
Then I read about the stipple argument to create_rectangle from here:
stipple: A bitmap indicating how the interior of the rectangle will
be stippled.
Default is stipple="", which means a solid color. A
typical value would be stipple='gray25'. Has no effect unless the fill
has been set to some color. See Section 5.7, “Bitmaps”.
And the section on bitmaps states that only a few stipple options are available by default, but none of them are completely transparent. However, you can specify your own custom bitmap as an X bitmap image (a .xbm file).
XBM files are really just text files with a C-like syntax, so I made my own 2x2 bitmap with all transparent pixels and saved it as transparent.xbm in the same directory as my Tkinter script. Here's the code for the XBM file:
#define trans_width 2
#define trans_height 2
static unsigned char trans_bits[] = {
0x00, 0x00
};
Then, you can specify the custom stipple by prefixing the xbm file name with a # when creating your rectangle:
self.canvas.create_rectangle(
x1,
y1,
x2,
y2,
outline='green',
fill='gray', # still needed or stipple won't work
stipple='#transparent.xbm',
width=2
)
Note, you still need to provided some fill value or the stipple will not be applied. The actual fill value doesn't matter as the stipple will "override" it in the canvas.
I think I got it: Bind the canvas, not the rectangle.
replace
self.canvas.tag_bind('CLICK_AREA','<Button>',self.onClickArea)
with
self.canvas.bind('<Button>',self.onClickArea)
problem solved.
Related
I created a canvas and inside I put an image. I also can change the properties of the watermark text and would like to update the text on the canvas when I make some changes.
I created the text inside of the canvas with create_text and when I initialize the program, I created a variable. text_variable = canvas.create_text(...) However, I couldn't also adjust the opacity of the text.
Problems:
I can't adjust the opacity
I can't update color, font style, font size and position after I put this text on the canvas.
I expect:
Change the text when I change some properties from the edit menu
Add opacity adjustment to the text
self.watermark_display = self.display_canvas.create_text(self.watermark_start_position_x, self.watermark_start_position_y, text="Plese write your watermark!", font=(self.fonttype.get(),self.fontsize.get()),fill=self.color_choice)
def update_watermark_display(self):
self.display_canvas.itemconfig(self.watermark_display, self.watermark_start_position_x, self.watermark_start_position_y, text="Plese write your watermark!", font=(self.fonttype.get(),self.fontsize.get()),fill=self.color_choice)
When I try to do with this way, I got Type Error.
self.display_canvas.itemconfig(self.watermark_display, self.watermark_start_position_x, self.watermark_start_position_y, text="Plese write your watermark!", font=(self.fonttype.get(),self.fontsize.get()),fill=self.color_choice)
TypeError: Canvas.itemconfigure() takes from 2 to 3 positional arguments but 4 were given
You cannot use itemconfig to change the coordinates. Instead, use the coords method for the coordinates, and itemconfig for the item configuration.
self.display_canvas.itemconfig(
self.watermark_display,
text="Plese write your watermark!",
font=(self.fonttype.get(),self.fontsize.get()),
fill=self.color_choice
)
self.display_canvas.coords(
self.watermark_display,
self.watermark_start_position_x,
self.watermark_start_position_y
)
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"))
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.
I'm working on a Kivy app that lets the user position images and text labels on a template. When they're done, the resulting image is cropped to fit the template.
I need all the empty space in the image to be clear, as I will be printing the image and don't want to waste ink. Kivy, however, fills all the empty space with black. Is there a way for Kivy's export_to_png() function to use a transparent background instead of a black one?
I could be wrong, but it looks like the transparent colour is hardcoded.
Looking at the source code it seems that ClearColor is hard-coded as black.
def export_to_png(self, filename, *args):
'''Saves an image of the widget and its children in png format at the
specified filename. Works by removing the widget canvas from its
parent, rendering to an :class:`~kivy.graphics.fbo.Fbo`, and calling
:meth:`~kivy.graphics.texture.Texture.save`.
.. note::
The image includes only this widget and its children. If you want
to include widgets elsewhere in the tree, you must call
:meth:`~Widget.export_to_png` from their common parent, or use
:meth:`~kivy.core.window.WindowBase.screenshot` to capture the whole
window.
.. note::
The image will be saved in png format, you should include the
extension in your filename.
.. versionadded:: 1.9.0
'''
if self.parent is not None:
canvas_parent_index = self.parent.canvas.indexof(self.canvas)
self.parent.canvas.remove(self.canvas)
fbo = Fbo(size=self.size, with_stencilbuffer=True)
with fbo:
ClearColor(0, 0, 0, 1)
ClearBuffers()
Scale(1, -1, 1)
Translate(-self.x, -self.y - self.height, 0)
I guess you could try updating the Widget module code to accept a parameter to set the ClearColor.
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