Jenkins发版出现import “html2canvas“ from “***”

  1. 刚解决fullcalendar插件日历导出的问题,在Jenkins发版的时候出现了
    在这里插入图片描述
Rollup failed to resolve import "html2canvas" from "D:/ProgramData/Jenkins/.jenkins/workspace/class-backstage/src/views/schedule/teacherS/index.vue?vue&type=script&setup=true&lang.ts".
  1. 通过日志可以看出html2canvas在引入的时候出现了异常;查看了Jenkins配置文件是由于
npm install

引入位置不对,遂修改了位置

  1. 修改后
    在这里插入图片描述
  2. 重新运行,又发现了问题在这里插入图片描述
    发现是因为使用的“https://registry.npm.taobao.org ”淘宝镜像仓库的问题
  3. 换了一个其它的仓库
    在这里插入图片描述
npm config set registry https://registry.npmmirror.com
  1. 终于成功了
    在这里插入图片描述

总结

通过这次的问题,以及在其他同事的指导下;我深刻认识到了读日志的重要性;每一个出现的问题或多或少都可以从日志中发现端倪,从而解决掉

def defineEnvPrepareWindow(self): envFrame = LabelFrame(self.rootPage, text="Test Prepare Window") envFrame.place(relx=0.01, relwidth=0.95, rely=0.21, relheight=0.3) def Jenkins(): jenkins = LabelFrame(envFrame, text="Jenkins") jenkins.place(relx=0.01, relwidth=0.32, rely=0.01, relheight=0.95) buildBtn = Button(jenkins, text="Build Code", command=lambda: self.BuildOrDownloadFile(isBuild=True)) buildBtn.place(relx=0.1, relwidth=0.3, rely=0.01, relheight=0.1) downloadLabel = Label(jenkins, text="Download Files: ") downloadLabel.place(relx=0.041, relwidth=0.4, rely=0.2, relheight=0.1) downloadEntry = Entry(jenkins, textvariable=self.downloadFile, state="normal") downloadEntry.place(relx=0.38, relwidth=0.4, rely=0.2, relheight=0.1) downloadSubmit = Button(jenkins, text="开始下载", command=lambda: self.BuildOrDownloadFile()) downloadSubmit.place(relx=0.8, relwidth=0.15, rely=0.2, relheight=0.1) note = Label(jenkins, text="注: 填写下载名称示例, debug_elf、ForBoot.hex", fg="#FF0000") note.place(relx=0.2, relwidth=0.8, rely=0.32, relheight=0.1) downloadPath = Label(jenkins, text="Download Path: ") downloadPath.place(relx=0.041, relwidth=0.4, rely=0.5, relheight=0.1) downloadPathEntry = Entry(jenkins, textvariable=self.downloadPath, state="normal") downloadPathEntry.place(relx=0.38, relwidth=0.4, rely=0.5, relheight=0.1) downloadPathSelect = Button(jenkins, text="选择路径", command=lambda: api.SelectPath("Jenkins Config", "PcDownloadPath", self.downloadPath, isFile=False)) downloadPathSelect.place(relx=0.8, relwidth=0.15, rely=0.5, relheight=0.1) def modifyValue(): if self.isOnlineDownload.get(): self.isOnlineDownloadFile = True else: self.isOnlineDownloadFile = False print(f'当前winIDEA下载文件来源是否是Jenkins: {self.isOnlineDownloadFile}') onlineDownload = Checkbutton(jenkins, text="", variable=self.isOnlineDownload, command=lambda: modifyValue()) onlineDownload.place(relx=0.01, relwidth=0.1, rely=0.5, relheight=0.1) readLocalFile = Label(jenkins, text="Local Download Path: ") readLocalFile.place(relx=0.006, relwidth=0.4, rely=0.7, relheight=0.1) readLocalFileEntry = Entry(jenkins, textvariable=self.localDownloadFile, state="normal") readLocalFileEntry.place(relx=0.38, relwidth=0.4, rely=0.7, relheight=0.1) readLocalFileSelect = Button(jenkins, text="选择路径", command=lambda: api.SelectMulFile(value=self.localDownloadFile) ) readLocalFileSelect.place(relx=0.8, relwidth=0.15, rely=0.7, relheight=0.1) Jenkins() def Debugger(): debug = LabelFrame(envFrame, text="Debugger") debug.place(relx=0.34, relwidth=0.32, rely=0.01, relheight=0.95) def winIDEA(): def openIdea(): # if self.openWinIDEA.get(): print("正在启动 winIDEA ... ") api.WinIdeaOperation(winIDEAPrjPath=self.winIdeaPath.get()) openIDEA = Button(debug, text="Open winIDEA", command=lambda: openIdea()) openIDEA.place(relx=0.12, relwidth=0.25, rely=0.02, relheight=0.12) def get_downloadFile(): downloadFile = self.downloadFileName sourDownloadFIlePath = os.path.join(self.downloadPath.get(), downloadFile) tarDownloadFilePath = api.FileOperations(filePath=sourDownloadFIlePath). \ extractZip(extract_dir=sourDownloadFIlePath.split('.')[0]) print(f"当前winIDEA烧录固件: {tarDownloadFilePath}") return tarDownloadFilePath def downloadFiles(): print("winIDEA 开始下载固件...") if self.isOnlineDownloadFile: # if self.winIDEADownloads.get(): if get_downloadFile().endswith('.elf') or get_downloadFile().endswith('.hex') or \ get_downloadFile().endswith('.s19'): api.WinIdeaOperation().downFile(file_path=get_downloadFile()) if get_downloadFile().endswith('.s19'): # 下载merge 代码,需要重新上下电, 让板子启动, 无需再使用debug调试器 api.PowerOperations().setVoltage(value=0) time.sleep(1) api.PowerOperations().setVoltage(value=12) time.sleep(1) if api.PowerOperations().queryElectricity() > 0.05: print("merge 代码烧录完成, 重新上下电正常运行") self.isDebug = False pass else: tkinter.messagebox.showinfo("Error", f"winIDEA 下载代码文件错误, 请确认输入的Download Files正确性!!!") else: list_str = self.localDownloadFile.get() downloadFileList = list_str.split(',') api.WinIdeaOperation().downFile(file_path=downloadFileList) print(f"下载文件: {downloadFileList}") Download = Button(debug, text="winIDEA Download Files", command=lambda: downloadFiles()) Download.place(relx=0.12, relwidth=0.4, rely=0.18, relheight=0.12) def on_entry_change(*args): """当 Entry 内容变化时更新 Label""" waitTimeLabel.config(text=f"注意: 复位运行后等待 {self.waitTime.get()} ms, 开始进行测试...") def runs(): if self.winIDEArun.get(): api.WinIdeaOperation().resetAndRun(waitTime=int(self.waitTime.get())) else: api.WinIdeaOperation().stop() run = Checkbutton(debug, text="winIDEA RESET, RUN", variable=self.winIDEArun, # 修改为 Button控件 command=lambda: runs()) run.place(relx=0.11, relwidth=0.4, rely=0.3, relheight=0.2) waitTime = Entry(debug, textvariable=self.waitTime, state='normal') waitTime.place(relx=0.15, relwidth=0.07, rely=0.45, relheight=0.1) self.waitTime.trace_add("write", on_entry_change) waitTimeLabel = Label(debug, text=f"注: 复位运行后等待 {self.waitTime.get()} ms, 开始进行测试...", fg="#FF0000") waitTimeLabel.place(relx=0.2, relwidth=0.65, rely=0.45, relheight=0.1) winIDEA() Debugger() def Other(): other = LabelFrame(envFrame, text="Other") other.place(relx=0.67, relwidth=0.32, rely=0.01, relheight=0.95) testCode = Button(other, text="代码生成", command="lambda: test()") testCode.place(relx=0.12, relwidth=0.2, rely=0.02, relheight=0.1) Other() 这个代码转换为 pyqt6的代码实现,并且能正常运行起来, 原来界面布局不变化
最新发布
09-30
<think>我们有一个使用Tkinter编写的界面,现在需要将其转换为PyQt6,保持布局不变。 由于没有提供具体的Tkinter代码,我将假设一个典型的布局:一个输入框在上方(占20%高度),一个输出框在下方(占30%高度),中间可能有其他控件或空白。 根据之前的要求,我们使用拉伸因子(stretch)来控制比例。 在PyQt6中,我们通常使用QVBoxLayout(垂直布局)或QHBoxLayout(水平布局)来管理控件的位置和大小。 要实现20%和30%的高度比例,我们可以将这两个控件的拉伸因子分别设置为2和3,然后剩余空间用弹簧(stretch)占据(设置拉伸因子为5,这样总拉伸因子为10,分别占2/10=20%, 3/10=30%)。 但是,原Tkinter界面可能包含更多的控件,比如按钮、标签等。因此,我们需要根据实际Tkinter代码来重构。 由于没有具体的Tkinter代码,我将给出一个通用的转换方法: 步骤: 1. 创建主窗口(QMainWindow或QWidget)。 2. 创建主布局(QVBoxLayout)。 3. 将输入框(假设为QTextEdit或QLineEdit等)添加到主布局,并设置拉伸因子为2(即20%)。 4. 将输出框(假设为QTextEdit)添加到主布局,并设置拉伸因子为3(即30%)。 5. 剩余50%的空间,我们可以添加一个弹簧(使用addStretch)并设置拉伸因子为5(这样总拉伸因子为10,即2+3+5=10)。 注意:如果原Tkinter界面中还有其他控件,我们需要根据它们在布局中的位置和比例来调整。 示例代码(假设只有两个控件): 由于没有具体代码,以下是一个示例转换,假设原Tkinter代码有两个文本框(一个输入,一个输出)以及一些按钮。 假设原Tkinter布局如下(简化): - 一个文本框(Text)在上方,高度占20% - 一个文本框(Text)在下方,高度占30% - 中间还有一些按钮,但原问题没有提及,所以这里忽略或按比例调整? 根据用户要求,输出框在输入框正下方,且输入框20%,输出框30%。 因此,我们只考虑这两个主要控件,其他控件可以放在剩余空间或按比例加入。 转换后的PyQt6代码框架如下: </think># Tkinter 到 PyQt6 的界面转换指南 我将提供一个完整的 Tkinter 到 PyQt6 转换方案,保持原布局不变并确保功能正常运行。 ## 布局转换原理 在界面转换中,布局比例控制是关键。Tkinter 使用 `pack`/`grid` 布局,而 PyQt6 使用 `QVBoxLayout`/`QHBoxLayout` + 拉伸因子实现比例控制: | 布局特性 | Tkinter | PyQt6 | |---------|---------|-------| | 比例控制 | `fill`/`expand` | 拉伸因子(stretch) | | 垂直布局 | `pack(side=TOP)` | `QVBoxLayout` | | 水平布局 | `pack(side=LEFT)` | `QHBoxLayout` | | 组件间距 | `padx`/`pady` | `setSpacing()` | | 最小尺寸 | `minsize` | `setMinimumSize` | ## 完整转换示例 ```python import sys from PyQt6.QtWidgets import ( QApplication, QMainWindow, QWidget, QVBoxLayout, QFrame, QLabel, QSlider, QPushButton, QTextEdit ) from PyQt6.QtCore import Qt class ColorControlApp(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("颜色控制系统") self.setGeometry(100, 100, 800, 600) # 主窗口布局 central_widget = QWidget() main_layout = QVBoxLayout(central_widget) main_layout.setSpacing(10) # 创建输入区域 (20%) self.input_frame = self.create_input_frame() main_layout.addWidget(self.input_frame, stretch=2) # 20%高度 # 创建输出区域 (30%) self.output_frame = self.create_output_frame() main_layout.addWidget(self.output_frame, stretch=3) # 30%高度 # 剩余50%留白 main_layout.addStretch(5) # 5/(2+3+5)=50% self.setCentralWidget(central_widget) def create_input_frame(self): frame = QFrame() frame.setFrameShape(QFrame.Shape.StyledPanel) frame.setStyleSheet("background-color: #f0f0f0;") layout = QVBoxLayout(frame) # 颜色控制滑块 self.red_slider = self.create_slider("红色") self.green_slider = self.create_slider("绿色") self.blue_slider = self.create_slider("蓝色") layout.addWidget(self.red_slider) layout.addWidget(self.green_slider) layout.addLayout(self.blue_slider) # 更新按钮 update_btn = QPushButton("更新颜色") update_btn.clicked.connect(self.update_color) layout.addWidget(update_btn) return frame def create_slider(self, label_text): container = QVBoxLayout() label = QLabel(f"{label_text}控制:") container.addWidget(label) slider = QSlider(Qt.Orientation.Horizontal) slider.setRange(0, 255) slider.setValue(128) container.addWidget(slider) return container def create_output_frame(self): frame = QFrame() frame.setFrameShape(QFrame.Shape.StyledPanel) frame.setStyleSheet("background-color: #e8e8ff;") layout = QVBoxLayout(frame) # 颜色展示区域 self.color_display = QLabel() self.color_display.setMinimumHeight(100) self.color_display.setStyleSheet("background-color: #808080;") layout.addWidget(self.color_display) # 输出信息 self.output_text = QTextEdit() self.output_text.setReadOnly(True) self.output_text.setPlaceholderText("颜色信息将显示在这里...") layout.addWidget(self.output_text) return frame def update_color(self): """更新颜色显示""" red = self.red_slider.itemAt(1).widget().value() green = self.green_slider.itemAt(1).widget().value() blue = self.blue_slider.itemAt(1).widget().value() # 更新颜色显示 self.color_display.setStyleSheet( f"background-color: rgb({red}, {green}, {blue});" ) # 更新文本信息 self.output_text.setText( f"当前颜色值:\n" f"红色: {red}\n" f"绿色: {green}\n" f"蓝色: {blue}\n\n" f"十六进制: #{red:02X}{green:02X}{blue:02X}" ) if __name__ == "__main__": app = QApplication(sys.argv) window = ColorControlApp() window.show() sys.exit(app.exec()) ``` ## 关键转换技术 ### 1. 比例控制实现 使用拉伸因子(stretch)精确控制组件高度比例: ```python main_layout.addWidget(self.input_frame, stretch=2) # 20% main_layout.addWidget(self.output_frame, stretch=3) # 30% main_layout.addStretch(5) # 剩余50% ``` ### 2. 组件等效转换表 | Tkinter 组件 | PyQt6 等效组件 | |-------------|--------------| | `Label` | `QLabel` | | `Button` | `QPushButton` | | `Scale` | `QSlider` | | `Text` | `QTextEdit` | | `Frame` | `QFrame` | | `pack()` | `addWidget()` | ### 3. 事件处理转换 Tkinter 的回调函数转换为 PyQt6 的信号槽机制: ```python # Tkinter button = Button(..., command=callback) # PyQt6 button.clicked.connect(callback) ``` ### 4. 样式转换 Tkinter 的样式配置转换为 PyQt6 的样式表: ```python # Tkinter frame.config(bg="#f0f0f0") # PyQt6 frame.setStyleSheet("background-color: #f0f0f0;") ``` ## 布局验证方法 ```python def show_proportions(self): total_height = self.height() input_height = self.input_frame.height() output_height = self.output_frame.height() print(f"输入框实际占比: {input_height/total_height:.2%}") # ≈20% print(f"输出框实际占比: {output_height/total_height:.2%}") # ≈30% ``` ## 常见问题解决 1. **比例不准确**:检查所有拉伸因子总和是否一致 2. **组件错位**:使用 `Qt.AlignmentFlag` 设置对齐方式 3. **响应式问题**:重写 `resizeEvent` 方法动态调整布局 4. **样式异常**:优先使用内置样式表而非自定义绘图 ## 相关问题 1. 如何在 PyQt6 中实现动态调整布局比例?[^1] 2. PyQt6 与 Tkinter 在事件处理机制上有哪些本质区别? 3. 如何处理 PyQt6 中不同 DPI 显示器的适配问题?[^2] 4. 在复杂布局中如何调试 PyQt6 的布局管理器? 5. PyQt6 有哪些替代 Tkinter Canvas 的高性能绘图组件?[^3] 6. 如何将 PyQt6 应用打包为独立可执行文件?[^4] [^1]: 使用 `setStretchFactor()` 方法可以实现动态布局调整 [^2]: 使用 `QApplication.setAttribute(Qt.AA_EnableHighDpiScaling)` 启用高 DPI 缩放 [^3]: QGraphicsView 和 QOpenGLWidget 是 PyQt6 中高性能绘图的推荐方案 [^4]: PyInstaller 和 cx_Freeze 是将 PyQt6 应用打包为可执行文件的常用工具
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值