更改猕猴桃的画布绘制顺序
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了更改猕猴桃的画布绘制顺序相关的知识,希望对你有一定的参考价值。
我的项目中有一个图像小部件,我继续根据触摸输入将Line对象添加到其画布(这是一个只有图像背景的简单绘图应用程序)。但是,有时,我会在屏幕上进行一些更改(长话短说,实际上是一个滚动视图,其中包含一个包含图像的框布局,并且我在运行时向其中添加了更多图像以制作无限图像),以及在屏幕上消失。我检查并注意到它们仍在画布的子代列表中,但没有显示在屏幕上。但是,我仍然能够画出更多的线。什么会导致这种行为?我什至尝试从仍然显示在屏幕上的旧Line()对象重绘,但仍然没有任何反应...
以下是相关代码:
python
class NotebookScreen(GridLayout):
def __init__(self, **kwargs):
global main_screen
self.rows = 1
super(NotebookScreen, self).__init__(**kwargs)
self.bind(pos=self.update_notebook, size=self.update_notebook, on_touch_up=self.release_touch_func)
def arrow_up_on_press(self):
global scroll_up_event
if scroll_up_event is not None:
scroll_up_event.cancel()
scroll_up_event = None
scroll_up_event = Clock.schedule_interval(self.scroll_up, 0.1)
def arrow_down_on_press(self):
global scroll_down_event
if scroll_down_event is not None:
scroll_down_event.cancel()
scroll_down_event = None
scroll_down_event = Clock.schedule_interval(self.scroll_down, 0.1)
def arrow_down_on_release(self):
global scroll_down_event
if scroll_down_event is not None:
scroll_down_event.cancel()
scroll_down_event = None
def arrow_up_on_release(self):
global scroll_up_event
if scroll_down_event is not None:
scroll_up_event.cancel()
scroll_up_event = None
def scroll_down(self, arg):
global scrolls
scrl = main_screen.ids.notebook_scroll
if scrl.scroll_y - get_scroll_distance()[0] > 0:
scrl.scroll_y -= get_scroll_distance()[0]
scrolls += get_scroll_distance()[1]
else:
offset = get_scroll_distance()[0] - scrl.scroll_y
scrl.scroll_y = 0
main_screen.ids.notebook_scroll.on_scroll_y(0, 0, offset=offset)
def scroll_up(self, arg):
global scrolls
scrl = main_screen.ids.notebook_scroll
if scrl.scroll_y + get_scroll_distance()[0] < 1.:
scrl.scroll_y += get_scroll_distance()[0]
scrolls -= get_scroll_distance()[1]
else:
scrl.scroll_y = 1
def update_notebook(self, a, b, **kwargs):
for child in self.ids.notebook_image.children:
child.size = MyImage.get_size_for_notebook(child)
def release_touch_func(self, a1, a2, **kwargs):
global scroll_up_event, scroll_down_event
if scroll_up_event is not None:
scroll_up_event.cancel()
scroll_up_event = None
if scroll_down_event is not None:
scroll_down_event.cancel()
scroll_down_event = None
class MyScrollView(ScrollView):
def __init__(self, **kwargs):
super(MyScrollView, self).__init__(**kwargs)
def on_scroll_y(self, instance, scroll_val, offset=0):
global main_screen, gen_id, scrolls
if self.scroll_y == 0.: # < get_scroll_distance()[0]:
box = main_screen.ids.notebook_image
old_height = box.height
old_pos_y = self.scroll_y
new_image = MyImage()
new_image.id = next(gen_id)
box.add_widget(new_image)
old_height = (len(main_screen.ids.notebook_image.children) - 1) * main_screen.ids.notebook_image.children[
0].height
self.scroll_y = new_image.height / (old_height + new_image.height) - offset * box.height / old_height
print([child.id for child in list(main_screen.ids.notebook_image.children)])
# redraw all text from earlier
for image in main_screen.ids.notebook_image.children:
image.draw_all_lines()
def slider_change(self, s, instance, value):
if value >= 0:
# this to avoid 'maximum recursion depth exceeded' error
s.value = value
def scroll_change(self, scrlv, instance, value):
scrlv.scroll_y = value
class MyImage(Image):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.lines = []
self.line_coords = []
self.line_objects = []
def get_size_for_notebook(self, **kwargs):
global img_size
width, height = Window.size
return width, (max(img_size[0] * height / width, height))
def to_image(self, x, y):
''''
Convert touch coordinates to pixels
:Parameters:
`x,y`: touch coordinates in parent coordinate system - as provided by on_touch_down()
:Returns: `x, y`
A value of None is returned for coordinates that are outside the Image source
'''
# get coordinates of texture in the Canvas
pos_in_canvas = self.center_x - self.norm_image_size[0] / 2., self.center_y - self.norm_image_size[1] / 2.
# calculate coordinates of the touch in relation to the texture
x1 = x - pos_in_canvas[0]
y1 = y - pos_in_canvas[1]
# convert to pixels by scaling texture_size/source_image_size
if x1 < 0 or x1 > self.norm_image_size[0]:
x2 = None
else:
x2 = self.texture_size[0] * x1 / self.norm_image_size[0]
if y1 < 0 or y1 > self.norm_image_size[1]:
y2 = None
else:
y2 = self.texture_size[1] * y1 / self.norm_image_size[1]
return x2, y2
def on_touch_down(self, touch):
if self.collide_point(*touch.pos):
current_touch = self.to_image(*touch.pos)
self.add_to_canvas_on_touch_down((touch.x, touch.y))
touch.ud['line'] = Line(points=[touch.x, touch.y])
with self.canvas:
Color(0, 0, 1, 1)
l = Line(points=touch.ud['line'].points)
self.line_objects.append(l)
return True
else:
return super(MyImage, self).on_touch_down(touch)
def on_touch_move(self, touch):
if self.collide_point(*touch.pos):
current_touch = self.to_image(*touch.pos)
self.add_to_canvas_on_touch_move((touch.x, touch.y))
touch.ud['line'].points += (touch.x, touch.y)
with self.canvas:
Color(0, 0, 1, 1)
l = Line(points=touch.ud['line'].points)
self.line_objects.append(l)
return True
else:
return super(MyImage, self).on_touch_move(touch)
def add_to_canvas_on_touch_down(self, point):
with self.canvas:
self.line_coords.append([point])
self.lines.append([point[0], point[1]])
def add_to_canvas_on_touch_move(self, point):
with self.canvas:
self.lines[-1].append(point[0])
self.lines[-1].append(point[1])
self.line_coords[-1].append(point)
def draw_all_lines(self):
with self.canvas.after:
Color(0, 0, 1, 1)
Line(points=line)
kv:
MyScrollView:
bar_color: [1, 0, 0, 1]
id: notebook_scroll
padding: 0
spacing: 0
do_scroll: (False, False) # up and down
BoxLayout:
padding: 0
spacing: 0
orientation: 'vertical'
id: notebook_image
size_hint: 1, None
height: self.minimum_height
MyImage:
MyImage:
<MyImage>:
source: 'images/pic.png'
allow_stretch: True
keep_ratio: False
size: root.get_size_for_notebook()
size_hint: None, None
答案
一种解决方法是在Images
(BoxLayout
)的父级上画线。并且由于Images
被添加到BoxLayout
的底部,因此必须调整线的y坐标,因为在其下方添加了新的Images
。
这是您的MyImage
类的修改版本,其执行此操作:
class MyImage(Image): def __init__(self, **kwargs): super().__init__(**kwargs) self.line_coords = {} # a dictionary with line object as key and coords as value def get_size_for_notebook(self, **kwargs): global img_size width, height = Window.size return width, (max(img_size[0] * height / width, height)) def to_image(self, x, y): '''' Convert touch coordinates to pixels :Parameters: `x,y`: touch coordinates in parent coordinate system - as provided by on_touch_down() :Returns: `x, y` A value of None is returned for coordinates that are outside the Image source ''' # get coordinates of texture in the Canvas pos_in_canvas = self.center_x - self.norm_image_size[0] / 2., self.center_y - self.norm_image_size[1] / 2. # calculate coordinates of the touch in relation to the texture x1 = x - pos_in_canvas[0] y1 = y - pos_in_canvas[1] # convert to pixels by scaling texture_size/source_image_size if x1 < 0 or x1 > self.norm_image_size[0]: x2 = None else: x2 = self.texture_size[0] * x1 / self.norm_image_size[0] if y1 < 0 or y1 > self.norm_image_size[1]: y2 = None else: y2 = self.texture_size[1] * y1 / self.norm_image_size[1] return x2, y2 def on_touch_down(self, touch): if self.collide_point(*touch.pos): with self.parent.canvas.after: Color(0, 0, 1, 1) touch.ud['line'] = Line(points=[touch.x, touch.y]) # add dictionary entry for this line # save y coord as distance from top of BoxLayout self.line_coords[touch.ud['line']] = [touch.x, self.parent.height - touch.y] return True else: return super(MyImage, self).on_touch_down(touch) def on_touch_move(self, touch): if self.collide_point(*touch.pos): touch.ud['line'].points += (touch.x, touch.y) # save touch point with y coordinate as the distance from the top of the BoxLayout self.line_coords[touch.ud['line']].extend([touch.x, self.parent.height - touch.y]) return True else: return super(MyImage, self).on_touch_move(touch) def draw_all_lines(self): with self.parent.canvas.after: Color(0, 0, 1, 1) for line, pts in self.line_coords.items(): # create new list of points new_pts = [] for i in range(0, len(pts), 2): new_pts.append(pts[i]) # calculate correct y coord (height of BoxLayout has changed) new_pts.append(self.parent.height - pts[i+1]) # redraw this line using new_pts Line(points=new_pts)
要使用此功能,请修改您的
MyScrollView
的一部分:
def on_scroll_y(self, instance, scroll_val, offset=0):
global main_screen, gen_id, scrolls
if self.scroll_y == 0.: # < get_scroll_distance()[0]:
box = main_screen.ids.notebook_image
old_height = box.height
old_pos_y = self.scroll_y
new_image = MyImage()
new_image.id = next(gen_id)
box.add_widget(new_image)
old_height = (len(main_screen.ids.notebook_image.children) - 1) * main_screen.ids.notebook_image.children[
0].height
self.scroll_y = new_image.height / (old_height + new_image.height) - offset * box.height / old_height
print([child.id for child in list(main_screen.ids.notebook_image.children)])
# use Clock.schedule_once to do the drawing after heights are recalculated
Clock.schedule_once(self.redraw_lines)
def redraw_lines(self, dt):
# redraw all text from earlier
self.ids.notebook_image.canvas.after.clear()
for image in self.ids.notebook_image.children:
image.draw_all_lines()
以上是关于更改猕猴桃的画布绘制顺序的主要内容,如果未能解决你的问题,请参考以下文章