鱼C论坛

 找回密码
 立即注册
查看: 2019|回复: 9

[技术交流] tkinter做的图片浏览器

[复制链接]
发表于 2019-9-20 19:04:07 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 一个账号 于 2020-3-7 13:37 编辑

1.jpg

ProgressBar.py
"""
A  basic widget for showing the progress
being made in a task.

"""

from tkinter import *


class ProgressBar:
    def __init__(self, master=None, orientation="horizontal",
                 min=0, max=100, width=100, height=18,
                 doLabel=1, appearance="sunken",
                 fillColor="blue", background="gray",
                 labelColor="yellow", labelFont="Verdana",
                 labelText="", labelFormat="%d%%",
                 value=50, bd=2):
        # preserve various values
        self.master = master
        self.orientation = orientation
        self.min = min
        self.max = max
        self.width = width
        self.height = height
        self.doLabel = doLabel
        self.fillColor = fillColor
        self.labelFont = labelFont
        self.labelColor = labelColor
        self.background = background
        self.labelText = labelText
        self.labelFormat = labelFormat
        self.value = value
        self.frame = Frame(master, relief=appearance, bd=bd)
        self.canvas = Canvas(self.frame, height=height, width=width, bd=0,
                             highlightthickness=0, background=background)
        self.scale = self.canvas.create_rectangle(0, 0, width, height,
                                                  fill=fillColor)
        self.label = self.canvas.create_text(self.canvas.winfo_reqwidth() / 2,
                                             height / 2, text=labelText,
                                             anchor="c", fill=labelColor,
                                             font=self.labelFont)
        self.update()
        self.canvas.pack(side='top', fill='x', expand='no')

    def updateProgress(self, newValue, newMax=None):
        if newMax:
            self.max = newMax
        self.value = newValue
        self.update()

    def update(self):
        # Trim the values to be between min and max
        value = self.value
        if value > self.max:
            value = self.max
        if value < self.min:
            value = self.min
        # Adjust the rectangle
        if self.orientation == "horizontal":
            self.canvas.coords(self.scale, 0, 0,
                               float(value) / self.max * self.width, self.height)
        else:
            self.canvas.coords(self.scale, 0,
                               self.height - (float(value) / self.max * self.height),
                               self.width, self.height)
        # Now update the colors
        self.canvas.itemconfig(self.scale, fill=self.fillColor)
        self.canvas.itemconfig(self.label, fill=self.labelColor)
        # And update the label
        if self.doLabel:
            if value:
                if value >= 0:
                    pvalue = int((float(value) / float(self.max)) * 100.0)
                else:
                    value = 0
                self.canvas.itemconfig(self.label, text=self.labelFormat % value)
            else:
                self.canvas.itemconfig(self.label, text='')
        else:
            self.canvas.itemconfig(self.label, text=self.labelFormat % self.labelText)
        self.canvas.update_idletasks()

AppShell.py
#! /usr/env/python

"""
AppShell provides a GUI application framework.

This is a streamlined adaptation of GuiAppD.py, originally
created by Doug Hellmann (doughellmann@mindspring.com).

"""

from tkinter import *
import Pmw
import sys, string
import ProgressBar


class AppShell(Pmw.MegaWidget):
    appversion = '1.0'
    appname = 'Generic Application Frame'
    copyright = 'Copyright YYYY Your Company. All Rights Reserved'
    contactname = 'Your Name'
    contactphone = '(999) 555-1212'
    contactemail = 'youremail@host.com'

    frameWidth = 450
    frameHeight = 320
    padx = 5
    pady = 5
    usecommandarea = 0
    balloonhelp = 1

    busyCursor = 'watch'

    def __init__(self, **kw):
        optiondefs = (
            ('padx', 1, Pmw.INITOPT),
            ('pady', 1, Pmw.INITOPT),
            ('framewidth', 1, Pmw.INITOPT),
            ('frameheight', 1, Pmw.INITOPT),
            ('usecommandarea', self.usecommandarea, Pmw.INITOPT))
        self.defineoptions(kw, optiondefs)

        self.root = Tk()
        self.initializeTk(self.root)
        Pmw.initialise(self.root)
        self.root.title(self.appname)
        self.root.geometry('%dx%d' % (self.frameWidth, self.frameHeight))

        # Initialize the base class
        Pmw.MegaWidget.__init__(self, parent=self.root)

        # initialize the application
        self.appInit()

        # create the interface
        self.__createInterface()

        # create a table to hold the cursors for
        # widgets which get changed when we go busy
        self.preBusyCursors = None

        # pack the container and set focus
        # to ourselves
        self._hull.pack(side=TOP, fill=BOTH, expand=YES)
        self.focus_set()

        # initialize our options
        self.initialiseoptions(AppShell)

    def appInit(self):
        # Called before interface is created (should be overridden).
        pass

    def initializeTk(self, root):
        # Initialize platform-specific options
        if sys.platform == 'mac':
            self.__initializeTk_mac(root)
        elif sys.platform == 'win32':
            self.__initializeTk_win32(root)
        else:
            self.__initializeTk_unix(root)

    def __initializeTk_colors_common(self, root):
        root.option_add('*background', 'grey')
        root.option_add('*foreground', 'black')
        root.option_add('*EntryField.Entry.background', 'white')
        root.option_add('*Entry.background', 'white')
        root.option_add('*MessageBar.Entry.background', 'gray85')
        root.option_add('*Listbox*background', 'white')
        root.option_add('*Listbox*selectBackground', 'dark slate blue')
        root.option_add('*Listbox*selectForeground', 'white')

    def __initializeTk_win32(self, root):
        self.__initializeTk_colors_common(root)
        root.option_add('*Font', 'Verdana 10 bold')
        root.option_add('*EntryField.Entry.Font', 'Courier 10')
        root.option_add('*Listbox*Font', 'Courier 10')

    def __initializeTk_mac(self, root):
        self.__initializeTk_colors_common(root)

    def __initializeTk_unix(self, root):
        self.__initializeTk_colors_common(root)

    def busyStart(self, newcursor=None):
        if not newcursor:
            newcursor = self.busyCursor
        newPreBusyCursors = {}
        for component in self.busyWidgets:
            newPreBusyCursors[component] = component['cursor']
            component.configure(cursor=newcursor)
            component.update_idletasks()
        self.preBusyCursors = (newPreBusyCursors, self.preBusyCursors)

    def busyEnd(self):
        if not self.preBusyCursors:
            return
        oldPreBusyCursors = self.preBusyCursors[0]
        self.preBusyCursors = self.preBusyCursors[1]
        for component in self.busyWidgets:
            try:
                component.configure(cursor=oldPreBusyCursors[component])
            except KeyError:
                pass
            component.update_idletasks()

    def __createAboutBox(self):
        Pmw.aboutversion(self.appversion)
        Pmw.aboutcopyright(self.copyright)
        Pmw.aboutcontact(
            'For more information, contact:\n %s\n Phone: %s\n Email: %s' % \
            (self.contactname, self.contactphone,
             self.contactemail))
        self.about = Pmw.AboutDialog(self._hull,
                                     applicationname=self.appname)
        self.about.withdraw()
        return None

    def showAbout(self):
        # Create the dialog to display about and contact information.
        self.about.show()
        self.about.focus_set()

    def toggleBalloon(self):
        if self.toggleBalloonVar.get():
            self.__balloon.configure(state='both')
        else:
            self.__balloon.configure(state='status')

    def __createMenuBar(self):
        self.menuBar = self.createcomponent('menubar', (), None,
                                            Pmw.MenuBar,
                                            (self._hull,),
                                            hull_relief=RAISED,
                                            hull_borderwidth=1,
                                            balloon=self.balloon())

        self.menuBar.pack(fill=X)
        self.menuBar.addmenu('Help', 'About %s' % self.appname, side='right')
        self.menuBar.addmenu('File', 'File commands and Quit')

    def createMenuBar(self):
        self.menuBar.addmenuitem('Help', 'command',
                                 'Get information on application',
                                 label='About...', command=self.showAbout)
        self.toggleBalloonVar = IntVar()
        self.toggleBalloonVar.set(1)
        self.menuBar.addmenuitem('Help', 'checkbutton',
                                 'Toggle balloon help',
                                 label='Balloon help',
                                 variable=self.toggleBalloonVar,
                                 command=self.toggleBalloon)

        self.menuBar.addmenuitem('File', 'command', 'Quit this application',
                                 label='Quit',
                                 command=self.quit)

    def __createBalloon(self):
        # Create the balloon help manager for the frame.
        # Create the manager for the balloon help
        self.__balloon = self.createcomponent('balloon', (), None,
                                              Pmw.Balloon, (self._hull,))

    def balloon(self):
        return self.__balloon

    def __createDataArea(self):
        # Create data area where data entry widgets are placed.
        self.dataArea = self.createcomponent('dataarea',
                                             (), None,
                                             Frame, (self._hull,),
                                             relief=GROOVE,
                                             bd=1)
        self.dataArea.pack(side=TOP, fill=BOTH, expand=YES,
                           padx=self['padx'], pady=self['pady'])

    def __createCommandArea(self):
        # Create a command area for application-wide buttons.
        self.__commandFrame = self.createcomponent('commandframe', (), None,
                                                   Frame,
                                                   (self._hull,),
                                                   relief=SUNKEN,
                                                   bd=1)
        self.__buttonBox = self.createcomponent('buttonbox', (), None,
                                                Pmw.ButtonBox,
                                                (self.__commandFrame,),
                                                padx=0, pady=0)
        self.__buttonBox.pack(side=TOP, expand=NO, fill=X)
        if self['usecommandarea']:
            self.__commandFrame.pack(side=TOP,
                                     expand=NO,
                                     fill=X,
                                     padx=self['padx'],
                                     pady=self['pady'])

    def __createMessageBar(self):
        # Create the message bar area for help and status messages.
        frame = self.createcomponent('bottomtray', (), None,
                                     Frame, (self._hull,), relief=SUNKEN)
        self.__messageBar = self.createcomponent('messagebar',
                                                 (), None,
                                                 Pmw.MessageBar,
                                                 (frame,),
                                                 # entry_width = 40,
                                                 entry_relief=SUNKEN,
                                                 entry_bd=1,
                                                 labelpos=None)
        self.__messageBar.pack(side=LEFT, expand=YES, fill=X)

        self.__progressBar = ProgressBar.ProgressBar(frame,
                                                     fillColor='slateblue',
                                                     doLabel=1,
                                                     width=150)
        self.__progressBar.frame.pack(side=LEFT, expand=NO, fill=NONE)

        self.updateProgress(0)
        frame.pack(side=BOTTOM, expand=NO, fill=X)

        self.__balloon.configure(statuscommand= \
                                     self.__messageBar.helpmessage)

    def messageBar(self):
        return self.__messageBar

    def updateProgress(self, newValue=0, newMax=0):
        self.__progressBar.updateProgress(newValue, newMax)

    def bind(self, child, balloonHelpMsg, statusHelpMsg=None):
        # Bind a help message and/or status message to a widget.
        self.__balloon.bind(child, balloonHelpMsg, statusHelpMsg)

    def interior(self):
        # Retrieve the interior site where widgets should go.
        return self.dataArea

    def buttonBox(self):
        # Retrieve the button box.
        return self.__buttonBox

    def buttonAdd(self, buttonName, helpMessage=None,
                  statusMessage=None, **kw):
        # Add a button to the button box.
        newBtn = self.__buttonBox.add(buttonName)
        newBtn.configure(kw)
        if helpMessage:
            self.bind(newBtn, helpMessage, statusMessage)
        return newBtn

    def __createInterface(self):
        self.__createBalloon()
        self.__createMenuBar()
        self.__createDataArea()
        self.__createCommandArea()
        self.__createMessageBar()
        self.__createAboutBox()
        #
        # Create the parts of the interface
        # which can be modified by subclasses
        #
        self.busyWidgets = (self.root,)
        self.createMenuBar()
        self.createInterface()

    def createInterface(self):
        # Override this method to create the interface for the app.
        pass

    def main(self):
        # This method should be left intact!
        self.pack()
        self.mainloop()

    def run(self):
        self.main()


class TestAppShell(AppShell):
    usecommandarea = 1

    def createButtons(self):
        self.buttonAdd('Ok',
                       helpMessage='Exit',
                       statusMessage='Exit',
                       command=self.quit)

    def createMain(self):
        self.label = self.createcomponent('label', (), None,
                                          Label,
                                          (self.interior(),),
                                          text='Data Area')
        self.label.pack()
        self.bind(self.label, 'Space taker')

    def createInterface(self):
        AppShell.createInterface(self)
        self.createButtons()
        self.createMain()


if __name__ == '__main__':
    test = TestAppShell(balloon_state='both')
    test.run()

Example_8_10.py
from tkinter import *
import Pmw
import os
import AppShell
from PIL import Image, ImageTk

# Load the PIL plugins for all image types...
for m in ["BmpImagePlugin", "GifImagePlugin", "JpegImagePlugin",
          "PpmImagePlugin", "TiffImagePlugin"]:
    try:
        __import__(m)
    except ImportError:
        pass  # ignore missing driver for now
Image._initialized = 1

path = "./icons/"
imgs = "./images/"


class Node:
    def __init__(self, master, tree, icon=None,
                 openicon=None, name=None, action=None):
        self.master, self.tree = master, tree
        self.icon = PhotoImage(file=icon)
        if openicon:
            self.openicon = PhotoImage(file=openicon)
        else:
            self.openicon = None
        self.width, self.height = 1.5 * self.icon.width(),1.5 * self.icon.height()
        self.name = name
        self.var = StringVar()
        self.var.set(name)
        self.text = Entry(tree, textvariable=self.var, bg=tree.bg,
                          bd=0, width=len(name) + 2, font=tree.font,
                          fg=tree.textcolor, insertwidth=1,
                          highlightthickness=1,
                          highlightbackground=tree.bg,
                          selectbackground="#044484",
                          selectborderwidth=0,
                          selectforeground='white')
        self.action = action
        self.x = self.y = 0  # drawing location
        self.child = []
        self.state = 'colapsed'
        self.selected = 0

    def addChild(self, tree, icon=None, openicon=None, name=None,
                 action=None):
        child = Node(self, tree, icon, openicon, name, action)
        self.child.append(child)
        self.tree.display()
        return child

    def deleteChild(self, child):
        self.child.remove(child)
        self.tree.display()

    def textForget(self):
        self.text.place_forget()
        for child in self.child:
            child.textForget()

    def deselect(self):
        self.selected = 0
        for child in self.child:
            child.deselect()

    def boxpress(self, event=None):
        if self.state == 'expanded':
            self.state = 'colapsed'
        elif self.state == 'colapsed':
            self.state = 'expanded'
        self.tree.display()

    def invoke(self, event=None):
        if not self.selected:
            self.tree.deselectall()
            self.selected = 1
            self.tree.display()
            if self.action:
                self.action(self.name)
        self.name = self.text.get()
        self.text.config(width=len(self.name) + 2)

    def displayIconText(self):
        tree, text = self.tree, self.text
        if self.selected and self.openicon:
            self.pic = tree.create_image(self.x, self.y,
                                         image=self.openicon)
        else:
            self.pic = tree.create_image(self.x, self.y,
                                         image=self.icon)
        text.place(x=self.x + self.width / 2, y=self.y, anchor=W)
        text.bind("<ButtonPress-1>", self.invoke)
        tree.tag_bind(self.pic, "<ButtonPress-1>", self.invoke, "+")
        text.bind("<Double-Button-1>", self.boxpress)
        tree.tag_bind(self.pic, "<Double-Button-1>",
                      self.boxpress, "+")

    def displayRoot(self):
        if self.state == 'expanded':
            for child in self.child:
                child.display()
        self.displayIconText()

    def displayLeaf(self):
        self.tree.hline(self.y, self.master.x + 1, self.x)
        self.tree.vline(self.master.x, self.master.y, self.y)
        self.displayIconText()

    def displayBranch(self):
        master, tree = self.master, self.tree
        x, y = self.x, self.y
        tree.hline(y, master.x, x)
        tree.vline(master.x, master.y, y)
        if self.state == 'expanded' and self.child != []:
            for child in self.child:
                child.display()
            box = tree.create_image(master.x, y,
                                    image=tree.minusnode)
        elif self.state == 'colapsed' and self.child != []:
            box = tree.create_image(master.x, y,
                                    image=tree.plusnode)
        tree.tag_bind(box, "<ButtonPress-1>", self.boxpress, "+")
        self.displayIconText()

    def findLowestChild(self, node):
        if node.state == 'expanded' and node.child != []:
            return self.findLowestChild(node.child[-1])
        else:
            return node

    def display(self):
        master, tree = self.master, self.tree
        n = master.child.index(self)
        self.x = master.x + self.width
        if n == 0:
            self.y = master.y + (n + 1) * self.height
        else:
            previous = master.child[n - 1]
            self.y = self.findLowestChild(previous).y + self.height
        if master == tree:
            self.displayRoot()
        elif master.state == 'expanded':
            if self.child == []:
                self.displayLeaf()
            else:
                self.displayBranch()
            tree.lower('line')


class Tree(Canvas):
    def __init__(self, master, icon, openicon, treename, action,
                 bg='white', relief='sunken', bd=2,
                 linecolor='#808080', textcolor='black',
                 font=('MS Sans Serif', 8)):
        Canvas.__init__(self, master, bg=bg, relief=relief, bd=bd,
                        highlightthickness=0)
        self.pack(side='left', anchor=NW, fill='both', expand=1)
        self.bg, self.font = bg, font
        self.linecolor, self.textcolor = linecolor, textcolor
        self.master = master
        self.plusnode = PhotoImage(file=path + 'plusnode.gif')
        self.minusnode = PhotoImage(file=path + 'minusnode.gif')
        self.inhibitDraw = 1
        self.imageLabel = None
        self.imageData = None
        self.child = []
        self.x = self.y = -10
        self.child.append(Node(self, self, action=action,
                               icon=icon, openicon=openicon, name=treename))

    def display(self):
        if self.inhibitDraw: return
        self.delete(ALL)
        for child in self.child:
            child.textForget()
            child.display()

    def deselectall(self):
        for child in self.child:
            child.deselect()

    def vline(self, x, y, y1):
        for i in range(0, int(abs(y - y1)), 2):
            self.create_line(x, y + i, x, y + i + 1, fill=self.linecolor,
                             tags='line')

    def hline(self, y, x, x1):
        for i in range(0, int(abs(x - x1)), 2):
            self.create_line(x + i, y, x + i + 1, y, fill=self.linecolor,
                             tags='line')


class ImageBrowser(AppShell.AppShell):
    usecommandarea = 1
    appname = 'Image Browser'

    def createButtons(self):
        self.buttonAdd('Ok',
                       helpMessage='Exit',
                       statusMessage='Exit',
                       command=self.quit)

    def createMain(self):
        self.panes = self.createcomponent('panes', (), None,
                                          Pmw.PanedWidget,
                                          (self.interior(),),
                                          orient='horizontal')
        self.panes.add('browserpane', min=150, size=160)
        self.panes.add('displaypane', min=.1)

        f = path + 'folder.gif'
        of = path + 'openfolder.gif'
        self.browser = self.createcomponent('browse', (), None,
                                            Tree,
                                            (self.panes.pane('browserpane'),),
                                            icon=f,
                                            openicon=of,
                                            treename='Multimedia',
                                            action=None)
        self.browser.pack(side=TOP, expand=YES, fill=Y)

        self.datasite = self.createcomponent('datasite', (), None,
                                             Frame,
                                             (self.panes.pane('displaypane'),))

        self.datasite.pack(side=TOP, expand=YES, fill=BOTH)

        f = path + 'folder.gif'
        of = path + 'openfolder.gif'
        gf = path + 'gif.gif'
        jf = path + 'jpg.gif'
        xf = path + 'other.gif'

        self.browser.inhibitDraw = 1

        top = self.browser.child[0]
        top.state = 'expanded'
        jpeg = top.addChild(self.browser, icon=f, openicon=of,
                            name='Jpeg', action=None)
        gif = top.addChild(self.browser, icon=f, openicon=of,
                           name='GIF', action=None)
        other = top.addChild(self.browser, icon=f, openicon=of,
                             name='Other', action=None)

        imageDir = {'.jpg': (jpeg, jf), '.jpeg': (jpeg, jf),
                    '.gif': (gif, gf), '.bmp': (other, xf),
                    '.ppm': (other, xf)}

        files = os.listdir(imgs)
        for file in files:
            r, ext = os.path.splitext(file)
            if ext:
                cont, icon = imageDir.get(ext, (None, None))
                if cont:
                    cont.addChild(self.browser, icon=icon,
                                  name=file, action=self.showMe)

        self.browser.inhibitDraw = 0
        self.browser.display()

        self.panes.pack(side=TOP,
                        expand=YES,
                        fill=BOTH)

    def createImageDisplay(self):
        self.imageDisplay = self.createcomponent('image', (), None,
                                                 Label,
                                                 (self.datasite,))
        self.browser.imageLabel = self.imageDisplay
        self.browser.imageData = None
        self.imageDisplay.place(relx=0.5, rely=0.5, anchor=CENTER)

    def createInterface(self):
        AppShell.AppShell.createInterface(self)
        self.createButtons()
        self.createMain()
        self.createImageDisplay()

    def showMe(self, dofile):
        if self.browser.imageData: del self.browser.imageData
        self.browser.imageData = ImageTk.PhotoImage(Image.open('%s%s' % (imgs, dofile)))
        self.browser.imageLabel['image'] = self.browser.imageData


if __name__ == '__main__':
    imageBrowser = ImageBrowser()
    imageBrowser.run()

程序引用图片(解压缩后放到程序同目录下)

Icons.zip (5.56 KB, 下载次数: 2)
images.zip (176.71 KB, 下载次数: 2)

完整代码+图片如下:

图像查看器.zip (198.42 KB, 下载次数: 16)

原程序是用python2.x编译的,我修改了几个地方,让它可以在python3.7上运行

这个程序里的目录结构应该很常见。

我之前看到批量图片下载工具NeoDownloader大概有类似的界面,那个程序未必是用python写的,但是用python的话,用爬虫加tkinter就可以做出类似的程序来。感兴趣的可以研究一下
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2019-9-20 19:06:26 | 显示全部楼层
很好,很好
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2019-9-21 17:23:36 | 显示全部楼层
一个账号 发表于 2019-9-21 15:50
不好,好文转载没有表明转载地址。

这是《Python与Tkinter编程》第八章里的一个例子Example_8_10.py,源码可以在这里下载
https://www.manning.com/books/python-and-tkinter-programming
这本书很古老了,但是体现了tkinter的博大精深
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-9-21 17:57:00 From FishC Mobile | 显示全部楼层
好清静啊
好文转载没人看
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2019-9-21 18:45:22 | 显示全部楼层
_2_ 发表于 2019-9-21 17:57
好清静啊
好文转载没人看

我也是被这个程序困扰了许久,感兴趣默默研究一下
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-9-22 08:36:18 | 显示全部楼层
这个好像有个PDF
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2019-9-22 12:27:07 | 显示全部楼层

目录结构应用很广泛嘛
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-9-28 08:51:36 | 显示全部楼层
自己做个图片浏览器,厉害
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-10-17 17:49:09 | 显示全部楼层
很强大
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-4-23 22:17:26 | 显示全部楼层
十分感谢楼主的无私分享~最近也在看这个程序,但最后的Example_8_10.py一直调不通~看到楼主帖子帮了我很大的忙~再次感谢!!!!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-11-26 20:44

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表