You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PyQt5 GUI程序无法显示,报AttributeError: 'Img_controller'无'ui'属性

PyQt5 GUI程序报错AttributeError: 'Img_controller' object has no attribute 'ui'排查与修复

问题描述

基于PyQt5开发GUI程序,参考教程仅修改img_controller.py模块,初始化Img_controller实例时传入Qt Designer生成的Ui_MainWindow实例,由该模块修改UI属性。原教程程序运行正常,但我的程序无法显示主窗口,报错AttributeError: 'Img_controller' object has no attribute 'ui'。已在Img_controller的__init__方法中设置self.ui = ui,问题依旧,附上代码请求排查。

错误原因分析

  • 核心问题:初始化顺序错误:Img_controller的__init__方法中,先调用self.read_img(self.img_path),而read_img会触发set_img_ratio,进而调用__update_img等需要访问self.ui的方法,但此时self.ui = ui还未执行,导致属性未定义报错。
  • 次要问题:
    1. __update_text_img_shape方法中使用未定义的self.origin_width和self.origin_height,需替换为已定义的self.orig_w和self.orig_h。
    2. 缩放逻辑混淆:set_img_ratio会将滑块值转换为指数缩放比例,但set_zoom_in/set_zoom_out直接操作转换后的比例值,导致缩放逻辑混乱,需区分滑块原始值(0-100)和实际缩放比例。
    3. read_img中计算bytesPerline时参数错误,应为图片宽度乘以通道数。

修复后的代码

修复后的img_controller.py

from PyQt5 import QtCore, QtGui
import cv2
from UI import Ui_MainWindow

class Img_controller(object):
    def __init__(self, ui:Ui_MainWindow, slider_value:int = 50):
        super(Img_controller, self).__init__()
        self.img_path = 'sad.jpg'
        self.slider_value = slider_value  # 保存滑块原始值(0-100)
        self.ui = ui  # 先赋值UI实例,再执行后续依赖UI的操作
        self.read_img(self.img_path)

    def read_img(self,img_path):
        try:
            self.img = cv2.imread(img_path)
            self.orig_h, self.orig_w, self.orig_c = self.img.shape
            self.img_path = img_path
        except:
            self.img = cv2.imread(self.img_path)
            self.orig_h, self.orig_w, self.orig_c = self.img.shape
        
        # 修正bytesPerline计算:宽度*通道数
        bytesPerline = self.orig_w * self.orig_c
        self.qimg = QtGui.QImage(self.img, self.orig_w, self.orig_h, bytesPerline, QtGui.QImage.Format_RGB888).rgbSwapped()
        self.origin_qpixmap = QtGui.QPixmap.fromImage(self.qimg)
        self.slider_value = 50        
        self.set_img_ratio()

    def set_img_ratio(self):
        # 根据滑块值计算缩放比例
        self.img_ratio = pow(10, (self.slider_value - 50)/50)
        qpixmap_height = self.orig_h * self.img_ratio
        self.qpixmap = self.origin_qpixmap.scaledToHeight(qpixmap_height)
        # 更新UI界面
        self.__update_img()
        self.__update_text_ratio()
        self.__update_text_img_shape()
        self.__update_text_file_path()

    def __update_img(self):
        self.ui.image_label.setPixmap(self.qpixmap)
        self.ui.image_label.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop)

    def __update_text_file_path(self):
        self.ui.label_filename.setText(f"File path = {self.img_path}")

    def __update_text_ratio(self):
        self.ui.label_resolution.setText(f"{int(100*self.img_ratio)} %")

    def __update_text_img_shape(self):
        current_text = f"Current img shape = ({self.qpixmap.width()}, {self.qpixmap.height()})"
        origin_text = f"Origin img shape = ({self.orig_w}, {self.orig_h})"
        self.ui.label_img_shape.setText(current_text + "\t" + origin_text)

    def set_zoom_in(self):
        self.slider_value = max(0, self.slider_value - 1)
        self.ui.slider.setValue(self.slider_value)  # 同步滑块UI值
        self.set_img_ratio()

    def set_zoom_out(self):
        self.slider_value = min(100, self.slider_value + 1)
        self.ui.slider.setValue(self.slider_value)  # 同步滑块UI值
        self.set_img_ratio()

    def set_slider_value(self, value):
        self.slider_value = value
        self.set_img_ratio()

修复后的controller.py

from PyQt5 import QtCore,QtWidgets,QtGui
from PyQt5.QtWidgets import QMainWindow,QFileDialog
from img_controller import Img_controller
from UI import Ui_MainWindow

class Ui_controller(QMainWindow):
    def __init__(self):
        super(Ui_controller,self).__init__()
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        self.setup_control()

    def setup_control(self):
        self.img_controller = Img_controller(ui = self.ui)

        self.ui.btn_open.clicked.connect(self.open_file)         
        self.ui.btn_zoomin.clicked.connect(self.img_controller.set_zoom_in)
        self.ui.btn_zoomout.clicked.connect(self.img_controller.set_zoom_out)
        self.ui.slider.valueChanged.connect(self.getslidervalue)


    def open_file(self):
        filename, filetype = QFileDialog.getOpenFileName(self, "Open file", "./")
        if filename:  # 增加判断,避免取消选择时报错
            self.init_new_picture(filename)

    def init_new_picture(self, filename):
        self.ui.slider.setValue(50)  # 使用标准setValue方法设置滑块值
        self.img_controller.read_img(filename)        

    def getslidervalue(self):        
        self.img_controller.set_slider_value(self.ui.slider.value())  # 移除多余的+1操作

内容的提问来源于stack exchange,提问作者Johnson Lin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 09:20:27