PyQt5气体分子模拟程序故障:点击添加按钮无分子显示求助
问题描述
我开发了一款基于PyQt5的气体分子模拟程序,预期点击UI中的Addmolecule按钮时,界面会随机显示分子,但实际无任何分子显示,终端(Visual Studio)也未报错,请求技术协助。
问题分析与修复方案
- QMainWindow布局错误:QMainWindow不能直接设置布局,必须通过
centralWidget承载布局。原代码直接给窗口实例设置布局,导致QGraphicsView没有正确显示在窗口中。 - 坐标范围错误:分子生成时使用窗口整体尺寸
self.width()/self.height(),但实际应该使用QGraphicsView视口的尺寸,否则分子可能生成在视图可见区域之外。 - 场景元素索引不匹配:
self.scene.items()[i]无法保证与self.molecules列表的顺序一致,应该将图形项直接关联到对应的分子字典中,避免索引错误。 - 定时器停止方法错误:使用
startTimer()创建的定时器,需要用killTimer()停止,而非timer.stop()。
修复后的完整代码
import sys import random import math from PyQt5.QtWidgets import QApplication, QMainWindow, QSlider, QLabel, QVBoxLayout, QWidget, QPushButton, QGraphicsEllipseItem, QGraphicsScene, QGraphicsView from PyQt5.QtGui import QPainter, QColor from PyQt5.QtCore import Qt from PyQt5 import uic form_ui = uic.loadUiType("qqq.ui")[0] class GasMoleculeWindow(QMainWindow, form_ui): def __init__(self): super().__init__() self.setupUi(self) self.setWindowTitle("Gas Molecule Simulation") self.setGeometry(100, 100, 800, 600) self.molecules = [] self.temperature = 1.0 self.addMoleculeButton.clicked.connect(self.addMolecule) self.stopSimulation.clicked.connect(self.stopProgram) self.massSlider.setRange(1,10) self.massSlider.valueChanged.connect(self.updateMass) self.radiusSlider.valueChanged.connect(self.updateRadius) self.temperatureSlider.valueChanged.connect(self.updateTemperature) self.massLabel.setAlignment(Qt.AlignCenter) self.radiusLabel.setAlignment(Qt.AlignCenter) self.temperatureLabel.setAlignment(Qt.AlignCenter) self.scene = QGraphicsScene(self) self.view = QGraphicsView(self.scene) # 修复QMainWindow布局问题:使用centralWidget承载布局 central_widget = QWidget() self.setCentralWidget(central_widget) layout = QVBoxLayout(central_widget) layout.addWidget(self.view) self.timer_id = self.startTimer(10) # 重命名变量避免混淆 def addMolecule(self): # 获取视图视口的实际尺寸,作为分子生成的范围 view_width = self.view.viewport().width() view_height = self.view.viewport().height() for _ in range(10): molecule = { 'x': random.uniform(0, view_width), 'y': random.uniform(0, view_height), 'vx': random.uniform(-1, 1) * math.sqrt(3 * self.temperature / self.massSlider.value()), 'vy': random.uniform(-1, 1) * math.sqrt(3 * self.temperature / self.massSlider.value()), 'mass': self.massSlider.value(), 'radius': self.radiusSlider.value(), 'item': None # 预留存储图形项的位置 } self.molecules.append(molecule) molecule_item = QGraphicsEllipseItem( molecule['x'] - molecule['radius'], molecule['y'] - molecule['radius'], 2 * molecule['radius'], 2 * molecule['radius'] ) mass_color = self.getColorByMass(molecule['mass']) molecule_item.setBrush(QColor(*mass_color)) self.scene.addItem(molecule_item) molecule['item'] = molecule_item # 将图形项关联到分子字典 def getColorByMass(self, mass): min_mass = 1 max_mass = 10 min_color = QColor(0, 0, 255) # Blue max_color = QColor(255, 0, 0) # Red ratio = (mass - min_mass) / (max_mass - min_mass) r = int(min_color.red() + ratio * (max_color.red() - min_color.red())) g = int(min_color.green() + ratio * (max_color.green() - min_color.green())) b = int(min_color.blue() + ratio * (max_color.blue() - min_color.blue())) return r, g, b def updateMass(self): massValue = self.massSlider.value() self.massLabel.setText(f"Mass: {massValue}") def updateRadius(self): radiusValue = self.radiusSlider.value() self.radiusLabel.setText(f"Radius: {radiusValue}") def updateTemperature(self): temperatureValue = self.temperatureSlider.value() / 10.0 self.temperature = temperatureValue self.temperatureLabel.setText(f"Temperature: {temperatureValue}") for molecule in self.molecules: molecule['vx'] = random.uniform(-1, 1) * math.sqrt(3 * temperatureValue / molecule['mass']) molecule['vy'] = random.uniform(-1, 1) * math.sqrt(3 * temperatureValue / molecule['mass']) def timerEvent(self, event): if event.timerId() != self.timer_id: super().timerEvent(event) return view_width = self.view.viewport().width() view_height = self.view.viewport().height() for i in range(len(self.molecules)): molecule = self.molecules[i] molecule_item = molecule['item'] # 直接从字典获取关联的图形项 molecule['x'] += molecule['vx'] molecule['y'] += molecule['vy'] molecule_item.setRect( molecule['x'] - molecule['radius'], molecule['y'] - molecule['radius'], 2 * molecule['radius'], 2 * molecule['radius'] ) # 边界碰撞检测使用视图视口尺寸 if molecule['x'] < molecule['radius'] or molecule['x'] > view_width - molecule['radius']: molecule['vx'] *= -1 if molecule['y'] < molecule['radius'] or molecule['y'] > view_height - molecule['radius']: molecule['vy'] *= -1 for j in range(i + 1, len(self.molecules)): other_molecule = self.molecules[j] dx = other_molecule['x'] - molecule['x'] dy = other_molecule['y'] - molecule['y'] distance = math.sqrt(dx ** 2 + dy ** 2) if distance < molecule['radius'] + other_molecule['radius']: mass_sum = molecule['mass'] + other_molecule['mass'] dx_normalized = dx / distance dy_normalized = dy / distance v1x = molecule['vx'] v1y = molecule['vy'] v2x = other_molecule['vx'] v2y = other_molecule['vy'] u1 = v1x * dx_normalized + v1y * dy_normalized u2 = v2x * dx_normalized + v2y * dy_normalized v1 = ((molecule['mass'] - other_molecule['mass']) * u1 + 2 * other_molecule['mass'] * u2) / mass_sum v2 = ((other_molecule['mass'] - molecule['mass']) * u2 + 2 * molecule['mass'] * u1) / mass_sum molecule['vx'] += (v1 - u1) * dx_normalized molecule['vy'] += (v1 - u1) * dy_normalized other_molecule['vx'] += (v2 - u2) * dx_normalized other_molecule['vy'] += (v2 - u2) * dy_normalized molecule['x'] += random.uniform(-0.5, 0.5) molecule['y'] += random.uniform(-0.5, 0.5) self.view.viewport().update() def stopProgram(self): self.killTimer(self.timer_id) # 使用killTimer停止定时器 if __name__ == '__main__': app = QApplication(sys.argv) window = GasMoleculeWindow() window.show() app.exec_()
内容的提问来源于stack exchange,提问作者1207권태형
相关产品推荐
相关产品推荐

