I'd like to draw the x,y coordinates of a nested ellipse I have within the ellipse. However, I'm afraid I don't understand the object hierarchy enough for how to do that. I have tried adding a label event to be a child of the Ellipse, and I know it doesn't have a 'text' attribute that I can modify directly (as it's not a Button or a Label). Here's what I have:
MyWidget:
canvas.before:
Color:
rgba: 1,0,0,1
Ellipse:
size: min(self.size)*0.2, min(self.size)*0.2
pos: (self.x), (self.y)
Label:
text: unicode(self.x), unicode(self.y)
Error:
>> 40: Label:
41: text: unicode(self.x), unicode(self.y)
...
You can add only graphics Instruction in canvas.
So, I add it to a child of the Ellipse:
MyWidget:
canvas.before:
Color:
rgba: 1,0,0,1
Ellipse:
size: min(self.size)*0.2, min(self.size)*0.2
pos: (self.x), (self.y)
Label:
text: unicode(self.x), unicode(self.y)
>> 40: Label:
41: text: unicode(self.x), unicode(self.y)
...
You can add only graphics Instruction in canvas.
So, I try to put it in a canvas:
MyWidget:
canvas.before:
Color:
rgba: 1,0,0,1
Ellipse:
size: min(self.size)*0.2, min(self.size)*0.2
pos: (self.x), (self.y)
canvas:
Label:
text: unicode(self.x), unicode(self.y)
That doesn't have an error, but doesn't display any text.
Updating to address excellent answer below
MyWidget:
canvas.before:
Color:
rgba: 1,0,0,1
Ellipse:
size: min(self.size)*0.2, min(self.size)*0.2
pos: (self.x, self.y)
Label:
pos: (self.x,self.y)
size: min(self.size)*0.2, min(self.size)*0.2
text: "{},{}".format(str(self.x),str(self.y))
Gives me the following error:
44: Label:
>> 45: pos: (self.x, self.y)
46: size: min(self.size)*0.2, min(self.size)*0.2
47: text: "{},{}".format(str(self.x),str(self.y))
...
RuntimeError: maximum recursion depth exceeded while calling a Python object
I still can't get the text to appear /inside/ the Ellipse.
Your problem is that you cannot mix the canvas with widgets.
A way to think of it is that each widget has a canvas. You can draw what you like on that canvas, but the keyword there is draw - you can use kivy graphics instructions, like Ellipse or Rectangle or Line (or contextual instructions like Translate and Rotate). However, you can't use widgets. They don't work that way, they aren't things you draw on a canvas, they are widgets. When you add one widget to another with add_widget, one thing that happens is that its canvas is drawn on the canvas of the other, but this is kept to the canvases - it doesn't make sense to try and draw a whole widget on a canvas.
This is the root of all of your errors; Ellipse is not a widget. It doesn't have a canvas, it's only something you draw on a canvas. It can't have children because it isn't a widget. In kv language, the keyword canvas (and canvas.before etc.) doesn't mean there's a child widget called canvas, it's just a special syntax referring to the canvas of the parent widget.
So, to actually fix your problem, you need to take the Label out of the canvas. Something like the following should work:
MyWidget:
canvas.before:
Color:
rgba: 1,0,0,1
Ellipse:
size: min(self.size)*0.2, min(self.size)*0.2
pos: (self.x), (self.y)
Label:
pos: root.pos
size: min(self.size)*0.2, min(self.size)*0.2
text: unicode(self.x), unicode(self.y)
This is of course the normal syntax for making the Label just be a child of MyWidget. The important part is it's been given the same position and size as the ellipse so, since text is centered by default, the text will appear in the middle of the ellipse. If the text is long or something you might want to play with other things like setting text_size to automatically wrap, but that's a different problem.
Also, once you have multiple widgets with the same size description (like the size of both the Label and Ellipse in my example), it's often neater to move that calculation to a different place - for instance a NumericProperty of MyWidget. That way you can avoid code duplication, and also make it so that if you ever change the positioning requirements you can easily update both the Label and Ellipse simultaneously.
Related
I want to draw Graphics elements in an amCharts 5 stock chart, for example Lines. I would like to use the Line class but have only managed to draw using the lower level line api below. I have not managed to find anything in the documentation about how to anchor Graphics elements to bars.
The lines should be anchored to bars, ie:
start on a certain date and end on another date,
are horizontal,
should move with the chart in zoom and pan events,
there can be hundreds of lines on the chart.
What I have done so far is to take the stock chart example https://www.amcharts.com/docs/v5/charts/stock/ and now I want to draw lines anchored to bars, which I'm failing to do. I did manage to draw a line but it is not anchored to any bar and does not move on zoom or pan.
How can I anchor Lines to bars, please?
Here is the code to draw a horizontal line:
mainPanel.plotContainer.children.push(am5.Graphics.new(root, {
stroke: am5.color(0x000000),
fill: am5.color(0x990000),
x: 20,
y: 70,
centerX: am5.percent(50),
centerY: am5.percent(50),
position: 'relative', // this did not do anything
draw: function(display) {
display.moveTo(0, 50);
display.lineTo(50, 50);
},
}));
I'm trying to use Squib to generate a map for a boardgame by printing one "card" which is the size of an entire A4 sheet of paper.
There must be some default in Squib that is cropping the resulting images and text, however, so that only a portion of it is visible.
Here is some sample code demonstrating the problem:
require 'squib'
Squib::Deck.new cards: 1, layout: [] do
rect x: 0, y: 0, width: 3457, height: 2438, fill_color: 'BLUE'
circle x: 1728, y: 1218 , radius: 1218, fill_color: 'RED'
save_pdf file: 'maps_1.pdf'
end
At 300 dpi, a landscape A4 piece of paper should be 3457x2438 pixels, so this ought to display a blue box with a red circle, filling the page. Instead it displays a poker-card-sized chunk of that image in the upper left hand corner:
resulting pdf
The result is much the same if I use millimeters, with a sprue:
require 'squib'
Squib::Deck.new cards: 1, layout: [] do
rect x: 0, y: 0, width: '295mm', height: '208mm', fill_color: 'BLUE'
circle x: '147.5mm', y: '104mm' , radius: '104mm', fill_color: 'RED'
save_pdf file: 'maps_1.pdf', sprue: 'layouts/map-sprue.yml'
end
Sprue:
---
sheet_width: 297mm
sheet_height: 210mm
card_width: 295.0mm
card_height: 208.0mm
cards:
- x: 0.0mm
y: 0.0mm
crop_line:
lines:
- type: :vertical
position: 0.0mm
- type: :vertical
position: 295.0mm
- type: :horizontal
position: 0.0mm
- type: :horizontal
position: 208.0mm
Does anyone know what is forcing squib only to address a portion of the A4 page?
thanks
You want width and height as parameters to Squib::Deck.new
To make your "card" the entire size of an A4 page, use something like this:
Squib::Deck.new(width: '210mm', height: '297mm') do
end
HOWEVER If you are planning on printing to an A4 page I recommend making it a tad smaller so that your printer doesn't autoscale or cut things off. My printer does fine with 6mm margin, probably something like 200x290.
You probably don't need sprues in this situation.
I'm having difficulty in positioning a label that has an image added using canvas within a scrollview. The desirable output is to have a label with text content as a paragraph followed by a label with an image and then followed by another label with text content as a paragraph.
The image is displaying in the correct position vertically as in its between the two text labels, but it is not positioning center when I attempt to scale down the image by multiplying the self.parent.width by .9 or whatever the decimal. It's binding it to the left screen and padding in the label is not working whereas it does work in the labels with text content. I have searched for documentation and other examples but could not find a solution to this. If anyone has experience with this or can provide any guidance, I'd greatly appreciate it. Please see my code below:
BoxLayout:
size_hint_y: .7
orientation: 'vertical'
canvas.before:
Color:
rgba: rgba('#FFFFFF')
Rectangle:
pos: self.pos
size: self.size
ScrollView:
id: sv
size_hint_y: None
height: self.parent.height
effect_cls: 'ScrollEffect'
GridLayout:
id: Content
cols: 1
size: self.minimum_size
size_hint: (1, None)
height: labelscroll1.texture_size[1]
Label:
id: labelscroll1
padding: ['20dp', '0dp']
color: rgba('#000000')
font_size: mtx.sp(14)
text_size: self.width, None
size: self.parent.width, self.texture_size[1]
size_hint: (None,None)
text: "Some text"
Label:
id: labelscroll2
padding: ['5dp','0dp']
size_hint: (None, None)
width: max(self.texture_size[0], self.parent.width)
height: 300
halign: 'center'
markup: True
canvas.before:
Rectangle:
pos: self.pos
size: self.size
source: 'Table.png'
Label:
id: labelscroll3
padding: ['20dp', '0dp']
color: rgba('#000000')
font_size: mtx.sp(14)
text_size: self.width, None
size: self.parent.width, self.texture_size[1]
size_hint: (None,None)
text: "Some text"
The indentations are four spaces in actual code but the formatting might be slightly off in here due to pasting.
Without seeing your actual code, I can only guess at what the problem actually is. But a good way to get something centered within a GridLayout cell is to use the AnchorLayout. Try replacing your middle Label in your kv with:
AnchorLayout:
size_hint: (1.0, None)
height: 300
Label:
id: labelscroll2
padding: ['5dp','0dp']
size_hint: (None, None)
width: max(self.texture_size[0], self.parent.width)
height: 300
halign: 'center'
markup: True
canvas.before:
Rectangle:
pos: self.pos
size: self.size
source: 'Table.png'
I tried scrolling by pixel unit and it does not seem to scroll by that exact amount of pixels. It scrolls disproportionately more.
I would like to scroll by pixels instead of whatever this pixel unit seems to represent.
Here is the code I use to scroll:
let event = CGEvent.init(scrollWheelEvent2Source: nil, units: .pixel, wheelCount: 1, wheel1: Int32(0), wheel2: Int32(0), wheel3: 0)!
event.setIntegerValueField(.scrollWheelEventDeltaAxis1, value: Int64(yPixels / 2))
event.setIntegerValueField(.scrollWheelEventDeltaAxis2, value: Int64(xPixels))
event.post(tap: .cgSessionEventTap)
I am having alot of issues trying to add an image to Scatter in Kivy. I want the image to first appear the same height as the boxlayout. Then I would like to be able to move and scale it (this does work currently). When I run the code the image shows up very small. I would also like the image to resize itself if the size of the window is changed. I am new to kivy so any help would be great. Thanks!
<MyGridLayout>:
rows: 1
BoxLayout:
id:layout1
orientation: 'vertical'
BoxLayout:
id: box1
size_hint : [1,0.5]
StencilView:
ScatterLayout:
center_x: box1.center_x
center_y: box1.center_y
Image:
source: 'histo_test.png'
size_hint_y: None
size_hint_x: None
width: self.parent.width
height: self.parent.width/self.image_ratio
center: self.parent.center
allow_stretch: True
keep_ratio: True
BoxLayout:
size_hint : [1,0.5]
id:box2
StencilView:
ScatterLayout:
center_x: box2.center_x
center_y: box2.center_y
Image:
source: 'flower.png'
size_hint_y: None
size_hint_x: None
width: self.parent.width
height: self.parent.width/self.image_ratio
center: self.parent.center
allow_stretch: True
keep_ratio: True
The size of the image must be the size of the StencilView, so:
size: stencil.width, stencil.height
or
width: stencil.width
height: stencil.width/self.image_ratio
(stencil is the id of the StencilView)
And the size of the ScatterLayout must be the size of the image:
size: my_image.size
(my_image is the id of the image)
Also you can set the position of the ScatterLayout with the position of the StencilView:
pos: stencil.pos
instead of this:
center_x: box1.center_x
center_y: box1.center_y
Watch this video for more info.
I wrote this code which does almost the same
<MyGridLayout>:
orientation: 'vertical'
StencilView:
id: stencil1
Scatter:
pos: stencil1.pos
size: my_image1.size
Image:
id: my_image1
size: stencil1.width, stencil1.height
source: 'dog.jpg'
allow_stretch: True
keep_ratio: False
StencilView:
id: stencil2
Scatter:
pos: stencil2.pos
size: my_image2.size
Image:
id: my_image2
size: stencil2.width, stencil2.height
source: 'flower.jpg'
allow_stretch: True
keep_ratio: False
Sorry if my english isn't clear