I am drawing a table on reportlab canvas. While drawing, we need to pass bottom left coords of the table to the drawOn method. The height of my table is dynamic and therefore it overlaps on the elements above the table. I couldnot find any method that returns the height of a table that is to be drawn. Is there an alternate way to do that?
This is such a simple thing that is passively demonstrated but not explicitly addressed in the reportlab documentation:
t = Table(tableData, style=tStyle)
t.canv = myCanvas
w, h = t.wrap(0, 0)
The variables w and h will then store the table's width and height, respectively.
Related
I cannot seem to get the scroll on this text to work. The text will scroll to a certain extent, but then not appear afterwards. I believe that the height of the text widget is not what I want. For instance, the image below shows only about a half of what the actual result is for 遺伝子 (which I can find out by attempting to drag from a piece of text in the middle of the frame to the bottom). The width also is not the same size of the frame I would like it to be: the number 23 was just something that appeared to work.
If I do
txt = tk.Text(self.SEARCH_RESULTS_TEXT_FRAME,width=self.SEARCH_RESULTS_FRAME_WIDTH,height=20,background='#d9d9d9',relief=RIDGE)
... the width becomes much too large. I would have thought that it would only take up the size of the frame, which is 240.
Note the SEARCH_RESULTS_TEXT_FRAME is the frame in red.
Relevant code:
#search text frame
self.SEARCH_RESULTS_FRAME_HEIGHT = 240 #240
self.SEARCH_RESULTS_FRAME_WIDTH = self.TITLE_FRAME_WIDTH - 23
self.SEARCH_RESULTS_TEXT_FRAME = Frame(self.SEARCH_RESULTS_FRAME,height=self.SEARCH_RESULTS_FRAME_HEIGHT,width=self.SEARCH_RESULTS_FRAME_WIDTH)
self.SEARCH_RESULTS_TEXT_FRAME.place(x=10,y=10,anchor = NW)
self.SEARCH_RESULTS_TEXT_FRAME.config(background ="#adadad")
def print_dict_to_frame(self,results_list):
txt = tk.Text(self.SEARCH_RESULTS_TEXT_FRAME,width=34,height=20,background='#d9d9d9',relief=RIDGE)
txt.place(x=0,y=0)
txt.tag_configure('header',justify = 'center',font=("Meiryo",12,'bold'))
txt.tag_configure('entry',font=('Meiryo',8))
for r_list in results_list:
header = r_list[0]
entry = r_list[1]
txt.insert(tk.END, "{}\n".format(header),'header')
for single_result in entry:
txt.insert(tk.END,single_result+"\n",'entry')
txt.configure(state=DISABLED)
How can I get the text widget to only take up the width of the frame and the height of the frame, allowing for scrolling?
If I do txt = tk.Text(self.SEARCH_RESULTS_TEXT_FRAME,width=self.SEARCH_RESULTS_FRAME_WIDTH,height=20,background='#d9d9d9',relief=RIDGE) ... the width becomes much too large. I would have thought that it would only take up the size of the frame, which is 240.
The width option specifies a width in the number of characters, not pixels. If you use the value 240, the width will be 240 multiplied times the width of an average character in the font you are using.
How can I get the text widget to only take up the width of the frame and the height of the frame, allowing for scrolling?
Give the text widget a width and height of 1, and then let the geometry manager (pack, place, or grid) be responsible for stretching it to fit the frame.
Since you're using place, you can use the relwidth and relheight options to make it the full size of the frame:
txt.place(x=0,y=0, anchor="nw", relwidth=1.0, relheight=1.0)
Personally, I recommend using pack or grid in almost all cases. It's much easier to create a responsive UI with them than it is with place.
Hi, I have created MainWindow as shown above. I want to expand the first widget (plots) as much as possible so that the other two widgets fit content (or actually, I want to remove white empty space below tables).
I don't know how to do that.
Currently, both table vertical header size policy is set to FitToContent.
Also, it needs to be dynamic so if I add a new row to the table, a new row should be visible (table will be larger).
I hope I'm clear enough, and also hope there is no need for runnable code.
Ok, I figure it out.
Reimplementing the resizeEvent will do the trick.
def resizeEvent(self, event):
super(Table, self).resizeEvent(event)
height = self.horizontalHeader().height()
for row in range(self.model().rowCount()):
height += self.rowHeight(row)
if self.horizontalScrollBar().isVisible():
height += self.horizontalScrollBar().height()
self.setMaximumHeight(height + 2)
I'm changing the height of QTableView. I'm including height of horizontal header + height of all rows + height of horizontalScrollBar if it is visible.
I have a texture that I want to repeat inside a Rectangle drawn by canvas.before. The problem is that I don't know what is going to be the size of the Rectangle (it's used as a background for its widget).
For example, I have a Rectangle that has 48 px height and width 100 - 500 px. I want to fill its content by horizontally repeating a 48x48 texture.
I know and tried setting texture.wrap = 'repeat' and texture.uvsize and it works correctly but only if I know the widget size beforehand. For example, setting uvsize = (3, 1) for a widget with size 144x48 works fine.
However, this doesn't work when I want to update uvsize before redrawing the widget. I created a canvas callback and updated uvsize there but this has no effect for some reason:
...
with self.canvas.before:
self.cb = Callback(self.on_canvas_redraw)
...
def on_canvas_redraw(self, instr):
self.texture.uvsize = (self.width / 48, 1)
So how can I dynamically update uvsize? Or is there a better way to handle widget resize or a better way to this altogether?
I am talking specific to python Tkinter, I have text along with a button in-lined and I am using pixel coordinates. Now my text string is changing dynamically, but if the text string is long then it overflows.
So I want if there any way if I can change the coordinates based on text length
For example:
canvas.create_text(20, 30, anchor=W, font="Purisa",
text="Most relationships seem so transitory")
If I use something like this
canvas.create_text(20+len(text), 30, anchor=W, font="Purisa",
text="Most relationships seem so transitory")
I am very new to tkinter and got a code to debug which is very tight, so I cannot change it dynamically in first place
You can calculate the coordinates based on the size of the text, but you need to find out the size of the text in the given font in pixels. This can be done in Tkinter by first using a scratch canvas and the bbox method. Create the text item and capture the id, then use the bbox method to get its size.
scratch = Canvas()
id = scratch.create_text((0, 0), text=text, <options>)
size = scratch.bbox(id)
# size is a tuple: (x1, y1, x2, y2)
# since x1 and y1 will be 0, x2 and y2 give the string width and height
Then you can calculate your x and y coordinates based on the results and draw it on your actual canvas. There is likely also a more efficient way to do this, but I don't know of it yet.
Or maybe you just want the x position to change based on the text size, in other words, making it right justified. In Tkinter this is most easily done by using the "anchor=E" option and giving the right edge of the text area for the x coordinate:
canvas.create_text(ButtonX - 10, 30, anchor=E, ...)
You can also use "width=200" for example to wrap the text in a 200 pixel wide box, in addition to anchor and any other options.
You can pass the "width" in create_text to avoid overflow.
width=Maximum line length. Lines longer than this value are wrapped. Default is 0 (no wrapping).
so it will be something like this
canvas.create_text(20, 30, anchor=W, font="Purisa",
text="Most relationships seem so transitory", width=0)
you can calculate the width based on the text size or make it fix, then if it is longer than it will be wrapped and there won't be any overflow.
I'm using Python and tkinter. I have a Canvas widget that will display just one image. Most times the image will be larger than the canvas dimensions, but sometimes it will be smaller. Let's just focus on the first case (image larger than canvas).
I want to scroll the canvas to an absolute position that I have already calculated (in pixels). How can I do that?
After trying for around half hour, I got another solution that seems better:
self.canvas.xview_moveto(float(scroll_x+1)/img_width)
self.canvas.yview_moveto(float(scroll_y+1)/img_height)
img_width and img_height are the dimensions of the image. In other words, they are the full scrollable area.
scroll_x and scroll_y are the coordinates of the desired top-left corner.
+1 is a magic value to make it work precisely (but should be applied only if scroll_x/y is non-negative)
Note that the current widget dimension is not needed, only the dimension of the contents.
This solution works very well even if the image is smaller than the widget size (and thus the scroll_x/y can be negative).
EDIT: improved version:
offset_x = +1 if scroll_x >= 0 else 0
offset_y = +1 if scroll_y >= 0 else 0
self.canvas.xview_moveto(float(scroll_x + offset_x)/new_width)
self.canvas.yview_moveto(float(scroll_y + offset_y)/new_height)
This is what I have already done:
# Little hack to scroll by 1-pixel increments.
oldincx = self.canvas["xscrollincrement"]
oldincy = self.canvas["yscrollincrement"]
self.canvas["xscrollincrement"] = 1
self.canvas["yscrollincrement"] = 1
self.canvas.xview_moveto(0.0)
self.canvas.yview_moveto(0.0)
self.canvas.xview_scroll(int(scroll_x)+1, UNITS)
self.canvas.yview_scroll(int(scroll_y)+1, UNITS)
self.canvas["xscrollincrement"] = oldincx
self.canvas["yscrollincrement"] = oldincy
But... As you can see... it's very hackish and ugly. To much workaround for something that should be simple. (plus that magic +1 I was required to add, or it would be off-by-one)
Does anyone else have another better and cleaner solution?
In tkinter you can get the width and height of a PhotoImagefile. You can just call it when you use canvas.create_image
imgrender = PhotoImage(file="something.png")
##Other canvas and scrollbar codes here...
canvas.create_image((imgrender.width()/2),(imgrender.height()/2), image=imgrender)
## The top left corner coordinates is (width/2 , height/2)
I found this solution by using self.canvas.scan_dragto(x, y)
Edit: I develop an interface which can scroll, zoom, and rotate an image. Let's extract from my interface the code.
When I want to save the current position of image I use this:
# 1) Save image position
x0canvas = -self.canvas.canvasx(0)
y0canvas = -self.canvas.canvasy(0)
x0, y0 = self.canvas.coords(text)
ximg = x0
yimg = y0
# 2) Restore image position (for example: after a load)
self.text = canvas.create_text(ximg, yimg, anchor='nw', text='')
self.xyscroll(x0canvas, y0canvas)
# Rotate and zoom image
image = Image.open('fileImg.jpg')
..
imageMod = image.resize(new_size)
if rotate != 0:
imageMod = imageMod.rotate(rotate)
imagetk = ImageTk.PhotoImage(imageMod)
imageid = canvas.create_image(canvas.coords(text), anchor='nw', image=imagetk)