簡體   English   中英

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM