[英]Kivy: How to populate a nested recycle view, which is inside popup with Kivy?
[英]Kivy - How to add screen in recycle view in gallery?
我使用過https://kivymd.readthedocs.io/en/latest/components/selection/並使用過https://github.com/stefanpetrescu997/imageGalleryImageThresholdingKivy 。
from kivy import app
from kivy.uix.screenmanager import Screen
from kivymd.app import MDApp
from kivy.metrics import dp
from kivy.lang.builder import Builder
import os
from PIL import Image as pillow
from kivy.utils import get_color_from_hex
from kivy.animation import Animation
import cv2
import numpy as np
from kivy.uix.textinput import TextInput
from kivy.uix.button import Button
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.image import Image
from kivy.uix.dropdown import DropDown
from kivy.core.window import Window
KV = """
<ImgCard@ButtonBehavior+BoxLayout>
path: ""
orientation: "vertical"
size_hint_y: None
on_release: app.root.viewimg(self)
on_release: app.on_selected(*args)
on_release: app.on_unselected(*args)
on_release: app.set_selection_mode(*args)
Image:
source: root.path
size_hint_y: .9
<GalleryApp>
orientation: 'vertical'
ScreenManager:
Screen:
BoxLayout:
orientation: 'vertical'
RecycleView:
id: img_base
viewclass: "ImgCard"
canvas.before:
#$#Color:
#$rgba: (.4, .4, .4, .7)
Rectangle:
size: self.size
pos: self.pos
RecycleGridLayout:
spacing: 10
cols: 3
default_size: None, dp(48)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
overlay_color: app.overlay_color[:-1] + [.2]
icon_bg_color: app.overlay_color
"""
class ImageManager(Screen):
pass
class GalleryApp(BoxLayout):
overlay_color = get_color_from_hex("#6042e4")
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.manager_list = []
self.dir = os.getcwd()
self.available_image_format = ['.png', '.jpg', '.jpeg', '.bmp'] # etc
def build(self):
return Builder.load_string(KV)
def on_start(self):
self.load_images()
def load_images(self):
if not self.manager_list:
for image in os.listdir(self.dir):
target_filename, target_file_extension = os.path.splitext(image)
if target_file_extension in self.available_image_format:
path_to_image = os.path.join(self.dir, image)
self.manager_list.append(
{
"ImgCard": "ImageManager",
"path": path_to_image,
"height": dp(200),
}
)
self.root.ids.img_base.data = self.manager_list
def next_image(self):
images = self.images
cur_idx = None
last_idx = len(images) -1
view_children = self.dir
cur_img = None
image_container = None
for child in view_children:
if str(child).find('BoxLayout') > -1:
image_container = child.children[0]
cur_img = image_container.source
for i, img in enumerate(images):
if img == cur_img:
cur_idx = i
if cur_idx != last_idx:
nxt_img = images[cur_idx+1]
else:
nxt_img = images[0]
image_container.source = nxt_img
def prev_image(self):
images = self.images
cur_idx = None
last_idx = len(images) -1
view_children = self.dir
cur_img = None
image_container = None
for child in view_children:
if str(child).find('BoxLayout') > -1:
image_container = child.children[0]
cur_img = image_container.source
for i, img in enumerate(images):
if img == cur_img:
cur_idx = i
if cur_idx != 0:
prev_img = images[cur_idx-1]
else:
prev_img = images[last_idx]
image_container.source = prev_img
def new_img_name(self):
view_children = self.dir
self.dir = view_children
new_name = TextInput(hint_text='New Image Name', multiline=False)
new_name.bind(on_text_validate=self.rename_img)
new_name_modal = ImageManager(size_hint=(None, None), size=(400, 50))
new_name_modal.add_widget(new_name)
new_name_modal.open()
def rename_img(self):
self.dir.dismiss()
new_name = self.dir.text
view_children = self.dir
cur_img = None
image_container = None
for child in view_children:
if str(child).find('BoxLayout') > -1:
image_container = child.children[0]
cur_img = image_container.source
ext = cur_img[cur_img.rfind('.'):]
def callback1(self, inst):
self.text1=self.txt_1.text
return self.text1
def callback2(self, inst):
self.text2=self.txt_2.text
return self.text2
def viewimg(self):
im = Image(source=app.path)
view_size = self.img_resize(im)
effects_drop = DropDown()
btn_prev = Button(text='Prev', size_hint_y=None, height = 50)
btn_prev.bind(on_release=self.prev_image)
btn_rename = Button(text='Rename', size_hint_y=None, height = 50)
btn_rename.bind(on_release=self.new_img_name)
btn_effects = Button(text='Effects', size_hint_y=None, height = 50)
btn_effects.bind(on_release=effects_drop.open)
btn_next = Button(text='Next', size_hint_y=None, height = 50)
btn_next.bind(on_release=self.next_image)
btn_black = Button(text='Grayscale', size_hint_y=None, height = 50)
btn_black.bind(on_release=self.black_image)
btn_bin = Button(text='Binarization', size_hint_y=None, height = 50)
btn_bin.bind(on_release=self.bin_image)
self.txt_1 = TextInput(hint_text='min', size_hint_y=None, height = 50, multiline = False)
#btn_1.bind(on_release=self.callback)
self.txt_1.bind(on_text_validate=self.callback1)
self.txt_2 = TextInput(hint_text='max', size_hint_y=None, height = 50, multiline = False)
#btn_bin.bind(on_release=self.bin_image)
self.txt_2.bind(on_text_validate=self.callback2)
effects_drop.add_widget(btn_black)
effects_drop.add_widget(btn_bin)
effects_drop.add_widget(self.txt_1)
effects_drop.add_widget(self.txt_2)
image_ops = BoxLayout(size_hint=(None, None), size=(400, 30), spacing=4)
image_ops.add_widget(btn_prev)
image_ops.add_widget(btn_rename)
image_ops.add_widget(btn_effects)
image_ops.add_widget(btn_next)
anchor = AnchorLayout(anchor_x='center', anchor_y='bottom')
anchor.add_widget(image_ops)
image_container = BoxLayout()
view = ImageManager(size_hint=(None,None),size=view_size)
image_container.add_widget(im)
view.add_widget(image_container)
view.add_widget(anchor)
view.open()
self.dir = view.children
def bin_image(self):
if self.txt_1.text == '' and self.txt_2.text=='':
minimum_minimorum = 0
maximum_maximorum = 255
elif self.txt_1.text == '' and self.txt_2.text!='':
minimum_minimorum = 0
maximum_maximorum = int(self.txt_2.text)
elif self.txt_1.text != '' and self.txt_2.text=='':
minimum_minimorum = int(self.txt_1.text)
maximum_maximorum = 255
else:
minimum_minimorum = int(self.txt_1.text)
maximum_maximorum = int(self.txt_2.text)
# print(self.txt_1.text)
# print(self.txt_2.text)
view_children = self.dir
cur_img = None
image_container = None
for child in view_children:
if str(child).find('BoxLayout') > -1:
image_container = child.children[0]
cur_img = image_container.source
im = pillow.open(cur_img)
open_cv_image = np.array(im)
retval, threshold = cv2.threshold(open_cv_image, minimum_minimorum, maximum_maximorum, cv2.THRESH_BINARY)
print(minimum_minimorum, maximum_maximorum)
new_im = pillow.fromarray(threshold)
name = im.filename[:-4] + '_bin' + im.filename[-4:]
im_cap = im.filename[im.filename.rfind('/')+1:]
new_im.save(name)
self.ids.img_base.data.insert(0, {'im_source':name, 'im_caption':im_cap})
self.ids.img_base.refresh_from_data()
image_container.source = name
def img_resize(self, img):
im_size_x, im_size_y = img.texture_size
ratio = im_size_x/im_size_y
aspect = self.aspect_ratio(ratio, 50)
while im_size_x >= Window.width or im_size_y >= Window.height:
if im_size_x > im_size_y:
im_size_x -= aspect[0]
im_size_y -= aspect[1]
else:
im_size_y -= aspect[1]
return [im_size_x, im_size_y]
def aspect_ratio(self, val, lim):
lower = [0, 1]
upper = [1, 0]
while True:
mediant = [lower[0] + upper[0], lower[1] + upper[1]]
if (val * mediant[1] > mediant[0]) :
if (lim < mediant[1]) :
return upper
lower = mediant
elif (val * mediant[1] == mediant[0]) :
if (lim >= mediant[1]) :
return mediant
if (lower[1] < upper[1]) :
return lower
return upper
else :
if (lim < mediant[1]) :
return lower
upper = mediant
def set_selection_mode(self, mode):
if mode:
md_bg_color = self.overlay_color
left_action_items = [
[
"close",
lambda x: self.root.ids.selection_list.unselected_all(),
]
]
right_action_items = [["trash-can"], ["dots-vertical"]]
else:
md_bg_color = (1, 1, 1, 1)
left_action_items = [["menu"]]
right_action_items = [["magnify"], ["dots-vertical"]]
self.root.ids.img_base.title = "Gallery"
Animation(md_bg_color=md_bg_color, d=0.2).start(self.root.ids.img_base)
self.root.ids.img_base.left_action_items = left_action_items
self.root.ids.img_base.right_action_items = right_action_items
def on_selected(self):
self.root.ids.img_base.title = str(
len(self.dir.get_selected_list_items())
)
def on_unselected(self):
if self.dir.get_selected_list_items():
self.root.ids.img_base.title = str(
len(self.dir.get_selected_list_items())
)
class Gallery(MDApp):
def build(self):
return GalleryApp()
if __name__=='__main__':
Gallery().run()
這是畫廊 但為什么畫廊里是空的? 但也要在其中添加選擇。 誰能幫我?
你永遠不會加載你的kv
字符串。 GalleryApp
類中的build()
方法未使用,可以刪除。 然后將對Builder
的調用添加到實際App
類的build()
方法中:
class Gallery(MDApp):
def build(self):
Builder.load_string(KV)
return GalleryApp()
您的代碼的基本問題是App
類和其他類之間的混淆。 您的GalleryApp
類不是App
類,但其中包含App
方法(如build()
和on_start()
)。 代碼中的實際App
類是Gallery
類。 也許類名選擇不當。
如前所述,您可以從GalleryApp
類中刪除build()
方法。 現在您需要稍加修改將on_start()
方法移動到App
類 ( Gallery
) 中:
class Gallery(MDApp):
overlay_color = get_color_from_hex("#6042e4")
def build(self):
Builder.load_string(KV)
return GalleryApp()
def on_start(self):
self.root.load_images()
請注意, KV
引用的overlay_color
也必須移動到正確的類中。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.