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

PyQt5启动报错:qt.qpa.plugin与QObject线程问题求助

解决PyQt5+OpenCV+MySQL整合代码的三类问题

问题列表与解决方案

1. sipPyTypeDict()弃用警告

原因:PyQt5与sip库版本不兼容,旧版sip的API已被弃用。
解决方法:

  • 升级sip到兼容版本:
    pip install --upgrade sip
    
  • 若升级后仍存在警告,同步更新PyQt5:
    pip install --upgrade PyQt5
    

2. QObject::moveToThread线程迁移错误

原因:OpenCV的Qt模块与PyQt5的线程上下文冲突,OpenCV初始化时创建的Qt对象无法迁移到PyQt主线程。
解决方法:
将cv2的导入时机延后到QApplication创建之后,避免线程初始化冲突:

if __name__ == '__main__':
    app = QApplication(sys.argv)
    import cv2  # 移至此处导入
    administrator = Administrator()
    main = Main()
    add_admin = AddAdmin()
    administrator.show()
    app.exec()

或者强制指定OpenCV使用非Qt后端:

import os
os.environ["OPENCV_UI_BACKEND"] = "GTK"  # 或设置为"none"禁用UI后端
import cv2

3. qt.qpa.plugin无法加载xcb插件(已找到但无法初始化)

原因:OpenCV自带的Qt插件与系统PyQt5的Qt库版本不匹配,或缺少xcb相关依赖。
解决方法:

  1. 指定PyQt5使用系统Qt插件:
    在代码开头添加环境变量,让PyQt优先调用系统自带的Qt插件,而非OpenCV自带的:
    import os
    # Ubuntu系统示例路径,其他发行版需调整
    os.environ["QT_PLUGIN_PATH"] = "/usr/lib/x86_64-linux-gnu/qt5/plugins"
    import cv2
    
  2. 安装完整的xcb依赖库:
    sudo apt-get install libxcb-cursor0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-shape0 libxcb-xkb1 libxkbcommon-x11-0
    
  3. 降级OpenCV版本:
    若新版本OpenCV与PyQt5兼容性差,尝试安装稳定旧版:
    pip install opencv-python==4.5.5.62
    

用户代码

import re
import sys
import webbrowser

import mysql.connector
from PyQt5.QtWidgets import QApplication, QDialog, QButtonGroup, QTableWidgetItem
from PyQt5.uic import loadUi
import cv2

try:
    db = mysql.connector.connect(host="localhost", user="root", password="", database="memoire")
    my_cursor = db.cursor()
    bd_connection = True
except mysql.connector.errors.DatabaseError:
    bd_connection = False


def administrator_window():
    administrator.show()
    add_admin.close()


def add_admin_window():
    add_admin.show()


def main_window():
    main.show()
    administrator.close()


class Administrator(QDialog):
    def __init__(self):
        super(Administrator, self).__init__()
        loadUi("ui/admin/administrator.ui", self)

        self.hide_icon()

        self.event_handler()

        self.pushButton_eye.clicked.connect(self.change_password_mode)
        self.button_validate.clicked.connect(self.check_connection)

    def event_handler(self):
        self.button_facebook.clicked.connect(
            lambda: webbrowser.open("https://web.facebook.com/UNHorizons/?_rdc=1&_rdr"))
        self.button_facebook.enterEvent = lambda event: self.label_facebook.show()
        self.button_facebook.leaveEvent = lambda event: self.label_facebook.hide()
        self.button_instagram.clicked.connect(lambda: webbrowser.open("https://www.instagram.com/unhorizons/"))
        self.button_instagram.enterEvent = lambda event: self.label_instagram.show()
        self.button_instagram.leaveEvent = lambda event: self.label_instagram.hide()
        self.button_youtube.clicked.connect(
            lambda: webbrowser.open("https://www.youtube.com/channel/UC7Y3KQIh7S6Y3vI41rsu9vQ"))
        self.button_youtube.enterEvent = lambda event: self.label_youtube.show()
        self.button_youtube.leaveEvent = lambda event: self.label_youtube.hide()

    def hide_icon(self):
        self.label_facebook.hide()
        self.label_instagram.hide()
        self.label_youtube.hide()

    def change_password_mode(self):
        current_echo_mode = self.lineEdit_pass.echoMode()

        if current_echo_mode == self.lineEdit_pass.Normal:
            self.lineEdit_pass.setEchoMode(self.lineEdit_pass.Password)
        elif current_echo_mode == self.lineEdit_pass.Password:
            self.lineEdit_pass.setEchoMode(self.lineEdit_pass.Normal)

    def check_connection(self):
        if bd_connection:
            identifier = self.lineEdit_email.text()
            password = self.lineEdit_pass.text()
            id_exists = False

            try:
                my_cursor.execute("SELECT * FROM administrator")
                result = my_cursor.fetchall()
                if not result:
                    print("empty")
                    self.label_error.clear()
                    add_admin_window()
                else:
                    for row in result:
                        if (identifier == row[3] or identifier == row[4]) and password == row[5]:
                            self.label_error.clear()
                            id_exists = True
                            Administrator.identifier = row[4]
                            main_window()
                    if not id_exists:
                        self.label_error.setText("Incorrect email address or password")
            except mysql.connector.errors.OperationalError:
                self.label_error.setText("Query expired, please try again later")

        else:
            self.label_error.setText("Connection impossible")


class Main(QDialog):
    def __init__(self):
        super(Main, self).__init__()
        loadUi("ui/admin/main_admin.ui", self)

        self.tableWidget.hide()

        self.pushButton_watch.clicked.connect(self.show_student)
        self.pushButton_scanner.clicked.connect(self.show_student)

    def show_student(self):
        self.tableWidget.show()
        try:
            my_cursor.execute("SELECT * FROM registration")
            result = my_cursor.fetchall()

            headers = [column_description[0] for column_description in my_cursor.description[1:]]
            self.tableWidget.setColumnCount(len(headers))
            self.tableWidget.setRowCount(len(result))
            self.tableWidget.setHorizontalHeaderLabels(headers)

            for row_index, row_data in enumerate(result):
                for column_index, cell_value in enumerate(row_data[1:]):
                    if column_index == 10 and cell_value is not None:
                        cell_value = "Existing QR code"
                    elif column_index == 11 and cell_value is not None:
                        cell_value = "Existing Profile"

                    item = QTableWidgetItem(str(cell_value))
                    self.tableWidget.setItem(row_index, column_index, item)
            self.tableWidget.resizeColumnsToContents()

        except mysql.connector.errors.OperationalError:
            self.label_error.setText("Query expired, please try again later")

    def scanner(self):
        try:
            print('3')
        except mysql.connector.errors.OperationalError:
            self.label_error.setText("Query expired, please try again later")


class AddAdmin(QDialog):
    def __init__(self):
        super(AddAdmin, self).__init__()
        loadUi("ui/admin/add_admin.ui", self)

        self.button_group = QButtonGroup()
        self.button_group.addButton(self.radio_male)
        self.button_group.addButton(self.radio_female)

        self.pushButton_validate.clicked.connect(self.check_registration)
        self.pushButton_cancel.clicked.connect(administrator_window)

    def check_registration(self):
        selected_radio = self.button_group.checkedButton()
        name = self.lineEdit_name.text()
        username = self.lineEdit_username.text()
        email = self.lineEdit_email.text()
        password = self.lineEdit_pass.text()
        confirm_password = self.lineEdit_pass_2.text()

        if selected_radio is not None:
            gender = selected_radio.text()
            if name and name.replace(' ', '').replace('-', '').isalpha():
                if username and username.replace('_', '').isalnum():
                    if re.match(r"[^@]+@[^@]+\.[^@]+", email):
                        if len(password) >= 5:
                            if password == confirm_password:
                                my_cursor.execute("SELECT * FROM administrator WHERE username = %s", (username,))
                                result = my_cursor.fetchone()

                                if result:
                                    self.label_error.setText("Username already in use")
                                else:
                                    my_cursor.execute("SELECT * FROM administrator WHERE email = %s", (email,))
                                    result = my_cursor.fetchone()

                                    if result:
                                        self.label_error.setText("Email already in use")
                                    else:
                                        my_cursor.execute("INSERT INTO `administrator`(`full_name`, `gender`, `username`, `email`, `password`) VALUES (%s, %s, %s, %s, %s)", (name, gender, username, email, password))
                                        db.commit()
                                        add_admin.close()
                            else:
                                self.label_error.setText("Incompatible passwords")
                        else:
                            self.label_error.setText("Password must be at least 5 characters long")
                    else:
                        self.label_error.setText("Invalid email address")
                else:
                    self.label_error.setText("Username must be alphanumeric")
            else:
                self.label_error.setText("Invalid name")
        else:
            self.label_error.setText("Please select a gender")


if __name__ == '__main__':
    app = QApplication(sys.argv)
    administrator = Administrator()
    main = Main()
    add_admin = AddAdmin()
    administrator.show()
    app.exec()

完整报错信息

/home/allan/Desktop/python/memoire/memoire_refactor/administrateur.py:32: DeprecationWarning: sipPyTypeDict() is deprecated, the extension module should use sipPyTypeDictRef() instead
  class Administrator(QDialog):
/home/allan/Desktop/python/memoire/memoire_refactor/administrateur.py:99: DeprecationWarning: sipPyTypeDict() is deprecated, the extension module should use sipPyTypeDictRef() instead
  class Main(QDialog):
/home/allan/Desktop/python/memoire/memoire_refactor/administrateur.py:141: DeprecationWarning: sipPyTypeDict() is deprecated, the extension module should use sipPyTypeDictRef() instead
  class AddAdmin(QDialog):
QObject::moveToThread: Current thread (0x55b67018b2d0) is not the object's thread (0x55b6708608e0).
Cannot move to target thread (0x55b67018b2d0)

qt.qpa.plugin: Could not load the Qt platform plugin "xcb" in "/home/allan/.local/lib/python3.10/site-packages/cv2/qt/plugins" even though it was found.
This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem.

Available platform plugins are: xcb, eglfs, linuxfb, minimal, minimalegl, offscreen, vnc, wayland-egl, wayland, wayland-xcomposite-egl, wayland-xcomposite-glx, webgl.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 13:17:03