# -*- coding: utf-8 -*- """把主窗口顶部 tabControl1(项目/报价/设置 三页签×24按钮)替换为 RibbonStrip 功能区(主功能区子类)。 改写 MainForm.Designer.cs / MainForm.cs / 主窗口.cs / MainForm.旧页签兼容.cs。 幂等:重复运行前先检查关键标记是否已存在。""" import io import re ROOT = r"C:\Users\099978\Documents\SharpDevelop Projects\成套报价软件\成套报价软件" # 24 个按钮: (原字段名, Text) BTN_PROJECT = [("button1", "新建项目"), ("button2", "修改项目"), ("button3", "删除项目"), ("button4", "打开项目"), ("button5", "复制项目")] BTN_PROJECT2 = [("button8", "导入项目"), ("button7", "导出项目")] BTN_QUOTE1 = [("button9", "打开项目"), ("button10", "修改项目"), ("button17", "保存")] BTN_QUOTE2 = [("button18", "导入报价"), ("button16", "甲方报表")] BTN_QUOTE3 = [("button15", "调母排"), ("button13", "调系数"), ("button33", "元件排序"), ("button29", "模板费用")] BTN_QUOTE4 = [("button11", "CAD扒图")] BTN_SET1 = [("btn登录", "登录"), ("btn修改密码", "修改密码"), ("btn会员信息", "会员信息")] BTN_SET2 = [("btn企业信息", "企业信息"), ("btn保存布局", "保存布局")] BTN_SET3 = [("btn备份", "备份"), ("btn恢复", "恢复")] ALL_BTNS = [b for grp in (BTN_PROJECT, BTN_PROJECT2, BTN_QUOTE1, BTN_QUOTE2, BTN_QUOTE3, BTN_QUOTE4, BTN_SET1, BTN_SET2, BTN_SET3) for b in grp] TAB_PAGES = ["tabPage项目", "tabPage报价", "tabPage设置"] BTN_NAMES = set(n for n, _ in ALL_BTNS) def read(p): with io.open(p, "r", encoding="utf-8-sig") as f: return f.read() def write(p, s): with io.open(p, "w", encoding="utf-8-sig") as f: f.write(s) def must_remove(line): """Designer.cs 里要删的行:24 按钮 + tabControl1 + 3 tabPage 的字段/new/suspend/resume/属性行。""" s = line.strip() # 按钮字段/new m = re.match(r"private System\.Windows\.Forms\.Button (button\d+|btn[^;]+);$", s) if m and m.group(1).strip() in BTN_NAMES: return True m = re.match(r"this\.(button\d+|btn[^ =]+) = new System\.Windows\.Forms\.Button\(\);$", s) if m and m.group(1) in BTN_NAMES: return True # 按钮属性行(this.buttonN.xxx = ...) m = re.match(r"this\.([A-Za-z0-9_]+)\.[A-Za-z0-9_]+ = ", s) if m and m.group(1) in BTN_NAMES: return True # tabControl1/tabPage if re.match(r"private System\.Windows\.Forms\.TabControl tabControl1;$", s): return True if s == "this.tabControl1 = new System.Windows.Forms.TabControl();": return True if s.startswith("this.tabControl1.") or s == "this.tabControl1.ResumeLayout(false);": return True for tp in TAB_PAGES: if re.match(r"private System\.Windows\.Forms\.TabPage %s;$" % tp, s): return True if s == "this.%s = new System.Windows.Forms.TabPage();" % tp: return True if s.startswith("this.%s." % tp) or s == "this.%s.ResumeLayout(false);" % tp: return True return False def ribbon_block(): """生成 ribbonStrip1 的 Designer 区块(tab 缩进)。""" t = "\t\t\t" L = [] L.append(t + "// ") L.append(t + "// ribbonStrip1") L.append(t + "// ") def tab(var, text): L.append(t + "Smart.CustomComponents.RibbonTab %s = new Smart.CustomComponents.RibbonTab();" % var) L.append(t + "%s.Text = \"%s\";" % (var, text)) def group(var, text): L.append(t + "Smart.CustomComponents.RibbonGroup %s = new Smart.CustomComponents.RibbonGroup();" % var) L.append(t + "%s.Text = \"%s\";" % (var, text)) def btn(field, text): var = "rbtn_" + field L.append(t + "Smart.CustomComponents.RibbonButton %s = new Smart.CustomComponents.RibbonButton();" % var) L.append(t + "%s.Name = \"%s\";" % (var, field)) L.append(t + "%s.Text = \"%s\";" % (var, text)) def add_group(var): L.append(t + "rtab1.Groups.Add(%s);" % var) def add_tab(): L.append(t + "this.ribbonStrip1.Tabs.Add(rtab1);") # ---- 页签1 项目 ---- tab("rtab1", "项目") group("rgrpA", "项目文件") for f, x in BTN_PROJECT: btn(f, x) L.append(t + "rgrpA.Buttons.Add(rbtn_%s);" % f) add_group("rgrpA") group("rgrpB", "数据") for f, x in BTN_PROJECT2: btn(f, x) L.append(t + "rgrpB.Buttons.Add(rbtn_%s);" % f) add_group("rgrpB") add_tab() # ---- 页签2 报价 ---- tab("rtab1", "报价") group("rgrpA", "项目") for f, x in BTN_QUOTE1: btn(f, x) L.append(t + "rgrpA.Buttons.Add(rbtn_%s);" % f) add_group("rgrpA") group("rgrpB", "报价") for f, x in BTN_QUOTE2: btn(f, x) L.append(t + "rgrpB.Buttons.Add(rbtn_%s);" % f) add_group("rgrpB") group("rgrpC", "计算") for f, x in BTN_QUOTE3: btn(f, x) L.append(t + "rgrpC.Buttons.Add(rbtn_%s);" % f) add_group("rgrpC") group("rgrpD", "工具") for f, x in BTN_QUOTE4: btn(f, x) L.append(t + "rgrpD.Buttons.Add(rbtn_%s);" % f) add_group("rgrpD") add_tab() # ---- 页签3 设置 ---- tab("rtab1", "设置") group("rgrpA", "账号") for f, x in BTN_SET1: btn(f, x) L.append(t + "rgrpA.Buttons.Add(rbtn_%s);" % f) add_group("rgrpA") group("rgrpB", "系统") for f, x in BTN_SET2: btn(f, x) L.append(t + "rgrpB.Buttons.Add(rbtn_%s);" % f) add_group("rgrpB") group("rgrpC", "数据") for f, x in BTN_SET3: btn(f, x) L.append(t + "rgrpC.Buttons.Add(rbtn_%s);" % f) add_group("rgrpC") add_tab() L.append(t + "this.ribbonStrip1.Dock = System.Windows.Forms.DockStyle.Top;") L.append(t + "this.ribbonStrip1.Location = new System.Drawing.Point(0, 0);") L.append(t + "this.ribbonStrip1.Name = \"ribbonStrip1\";") L.append(t + "this.ribbonStrip1.Size = new System.Drawing.Size(1884, 110);") L.append(t + "this.ribbonStrip1.TabIndex = 3;") return "\n".join(L) def replace_designer(src): lines = src.split("\n") out = [] i = 0 n = len(lines) while i < n: line = lines[i] s = line.strip() # 1) 按钮区块整体跳过:遇到 "// buttonN" 或 "// btnXxx" 标题行,连标题三行一起跳到区块尾 m = re.match(r"// (button\d+|btn[^ ]+)$", s) if m and m.group(1) in BTN_NAMES: i += 3 # 跳过 // 、// buttonN、// 三行 while i < n and lines[i].strip().startswith("this." + m.group(1) + "."): i += 1 continue # 2) tabControl1 区块跳过(注释头三行 + this.tabControl1.* 行),替换为 ribbonStrip1 区块 if s == "// tabControl1": i += 3 while i < n and lines[i].strip().startswith("this.tabControl1"): i += 1 out.append("\t\t\t// ") out.append("\t\t\t// ribbonStrip1") out.append("\t\t\t// ") out.append(ribbon_block()) # 跳过后续 3 个 tabPage 区块 for tp in TAB_PAGES: while i < n and lines[i].strip() != "// " + tp: i += 1 if i < n: i += 3 while i < n and lines[i].strip().startswith("this." + tp + "."): i += 1 continue # 3) 其余单行删除(字段/new/suspend/resume/Controls.Add(tabControl1)) if must_remove(line): i += 1 continue if s == "this.Controls.Add(this.tabControl1);": out.append(line.replace("tabControl1", "ribbonStrip1")) i += 1 continue out.append(line) i += 1 txt = "\n".join(out) # new 行与字段行插入 txt = txt.replace( "\t\t\tthis.tabControl1 = new System.Windows.Forms.TabControl();", "\t\t\tthis.ribbonStrip1 = new 主功能区();") txt = txt.replace( "\t\tprivate System.Windows.Forms.TabControl tabControl1;", "\t\tprivate 主功能区 ribbonStrip1;") return txt def replace_mainform_cs(src): # 1) 删 24 行 Click 挂接(button 系 12 行 + button15 lambda 段 + btn 系 5 行) pat_click = re.compile( r"[ \t]*this\.(button1|button3|button2|button5|button10|button16|button13|button18|button7|button8|button33|btn企业信息|btn备份|btn恢复|button11)\.Click \+= [^\n]*\n") src = pat_click.sub("", src) # button17 保存 src = re.sub(r"[ \t]*this\.button17\.Click \+= \(s, e\) => SaveAllToDatabase\(\);[^\n]*\n", "", src) # button15 lambda 整段(从注释行到闭括号行) src = re.sub( r"[ \t]*// ===== 调母排\(button15\):普通非模态弹窗 =====\n" r"[ \t]*// 不自动居中、不贴靠右侧、不跟随主窗口移动、不限制大小,直接弹出。\n" r"[ \t]*调母排 _tiaomuForm = null;\n" r"[ \t]*\n" r"[ \t]*this\.button15\.Click \+= \(s, e\) =>\n" r"[ \t]*\{.*?\n" r"[ \t]*\};\n", "", src, flags=re.S) # 2) tabControl1.SelectedIndexChanged 联动段替换为功能区事件 src = re.sub( r"[ \t]*// ===== 顶部选项卡:点击\"项目\"/\"报价\"时激活对应停靠文档窗口 =====\n" r"[ \t]*this\.tabControl1\.SelectedIndexChanged \+= \(s, e\) =>\n" r"[ \t]*\{.*?\n" r"[ \t]*\};\n", (" // ===== 功能区(ribbonStrip1):统一按钮点击路由 + 页签切换联动 =====\n" " this.ribbonStrip1.ButtonClick += ribbonStrip1_ButtonClick;\n" " this.ribbonStrip1.活动页已切换 += (s, e) =>\n" " {\n" " string tabName = (this.ribbonStrip1.ActiveTab != null) ? this.ribbonStrip1.ActiveTab.Text : \"\";\n" " Log(\"[TabSync] 功能区页签切换: [\" + tabName + \"]\");\n" " if (tabName == \"项目\" && this.w1 != null)\n" " {\n" " this.w1.Show(this.dockSurface1);\n" " this.w1.Activate();\n" " }\n" " else if (tabName == \"报价\" && this.w2 != null)\n" " {\n" " this.w2.Show(this.dockSurface1);\n" " this.w2.Activate();\n" " }\n" " // \"设置\"页只显示按钮面板,无停靠窗口\n" " };\n\n"), src, flags=re.S) return src def add_handlers(src): """在 MainForm 类尾部(canvas:找类的最后一个方法后)插入处理器与辅助方法。找 'private void Dgv_CellValuePushed' 所在文件不适用——直接加在构造器后第一个方法前。""" handlers = ''' // ============================================================ // 功能区(ribbonStrip1)按钮路由与辅助 // ============================================================ /// 功能区统一按钮点击:按 RibbonButton.Name(保留原按钮字段名)分发到原处理器。 private void ribbonStrip1_ButtonClick(object sender, Smart.CustomComponents.RibbonButtonEventArgs e) { if (e.Button == null || string.IsNullOrEmpty(e.Button.Name)) return; switch (e.Button.Name) { case "button1": button1_Click(sender, e); break; // 新建项目 case "button2": button2_Click(sender, e); break; // 修改项目(项目页) case "button3": button3_Click(sender, e); break; // 删除项目 case "button4": break; // 打开项目(项目页,原无处理器) case "button5": button5_Click(sender, e); break; // 复制项目 case "button7": button7_Click(sender, e); break; // 导出项目 case "button8": button8_Click(sender, e); break; // 导入项目 case "button9": break; // 打开项目(报价页,原无处理器) case "button10": button10_Click(sender, e); break; // 修改项目(报价页) case "button11": button11_Click(sender, e); break; // CAD扒图 case "button13": button13_Click(sender, e); break; // 调系数 case "button15": 打开调母排窗口(); break; // 调母排 case "button16": button16_Click(sender, e); break; // 甲方报表 case "button17": SaveAllToDatabase(); break; // 保存 case "button18": button18_Click(sender, e); break; // 导入报价 case "button29": break; // 模板费用(原无处理器) case "button33": button33_Click(sender, e); break; // 元件排序 case "btn登录": break; // 登录(原无处理器) case "btn修改密码": break; // 修改密码(原无处理器) case "btn企业信息": btn企业信息_Click(sender, e); break; // 企业信息 case "btn会员信息": break; // 会员信息(原无处理器) case "btn保存布局": btn保存布局_Click(sender, e); break; // 保存布局 case "btn备份": btn备份_Click(sender, e); break; // 备份 case "btn恢复": btn恢复_Click(sender, e); break; // 恢复 } } /// 按 Name 在功能区三层集合里找 RibbonButton(找不到返回 null)。 private Smart.CustomComponents.RibbonButton FindRibbonButton(string name) { if (this.ribbonStrip1 == null) return null; foreach (Smart.CustomComponents.RibbonTab tab in this.ribbonStrip1.Tabs) foreach (Smart.CustomComponents.RibbonGroup grp in tab.Groups) foreach (Smart.CustomComponents.RibbonButton btn in grp.Buttons) if (btn.Name == name) return btn; return null; } /// 调母排(button15):普通非模态弹窗(原构造器内 lambda 抽出)。 /// 不自动居中、不贴靠右侧、不跟随主窗口移动、不限制大小,直接弹出。 private 调母排 _调母排窗; private void 打开调母排窗口() { if (_调母排窗 != null && !_调母排窗.IsDisposed) { _调母排窗.Activate(); return; } if (string.IsNullOrWhiteSpace(_currentProjectId)) { MessageBox.Show(this, "请先在项目列表双击打开一个项目。", "调母排", MessageBoxButtons.OK, MessageBoxIcon.Information); return; } _调母排窗 = new 调母排(this); // 不设置 StartPosition/Location/Size/MaximumSize/MinimumSize,使用窗体自身默认值 _调母排窗.Show(this); _调母排窗.FormClosed += (s2, e2) => { _调母排窗 = null; }; } /// 项目菜单页"修改项目"按钮(项目页 button2):无条件可用,补路由。 private void button2_Click(object sender, EventArgs e) { 修改项目入口(); } ''' # button2_Click 原本存在?若存在会重复定义——先检查 if "private void button2_Click" in src and "ribbonStrip1_ButtonClick" not in src: # 已有 button2_Click,去掉补丁里的重复定义 handlers = handlers.replace(''' /// 项目菜单页"修改项目"按钮(项目页 button2):无条件可用,补路由。 private void button2_Click(object sender, EventArgs e) { 修改项目入口(); } ''', "") # 插入点:构造器结束后(锚点在构造器内,往后找第一个方法级结束括号 \t\t}) anchor = " // ===== 监听主区域 tabControl2 切换" idx = src.find(anchor) if idx < 0: raise SystemExit("MainForm.cs 找不到插入锚点") m = re.search(r"\n\t\t\}\n", src[idx:]) if not m: raise SystemExit("MainForm.cs 找不到构造器结束位置") pos = idx + m.end() return src[:pos] + handlers + "\n" + src[pos:] def replace_zhuwindow(src): # UpdateButton10State: button10 → FindRibbonButton src = src.replace( " this.button10.Enabled = onQuotePage && hasProject;", " var rb10 = FindRibbonButton(\"button10\");\n" " if (rb10 != null) rb10.Enabled = onQuotePage && hasProject;") # EnterProjectCore: tabControl1.SelectedTab = tabPage2 src = src.replace( " this.tabControl1.SelectedTab = this.tabPage2;\n" " Log(\"[EnterProjectCore] 已设 tabControl1.SelectedTab = tabPage2\");", " int 报价页idx = this.ribbonStrip1.页索引(\"报价\");\n" " if (报价页idx >= 0) this.ribbonStrip1.设活动页(报价页idx);\n" " Log(\"[EnterProjectCore] 已设功能区活动页=报价\");") return src def replace_compat(src): # 删 tabPage1/2/8 三个兼容属性 src = re.sub( r"[ \t]*// ---- 旧页签名 → 新控件别名(旧代码 this\.tabPageN 继续可用)----\n" r".*?public DockContent tabPage3 \{ get \{ return this\.w1; \} \}", " // ---- 旧页签名 → 新控件别名(旧代码 this.tabPageN 继续可用)----\n\n" " /// 旧左侧\"项目\"页 → 停靠窗口\"项目\"。\n" " public DockContent tabPage3 { get { return this.w1; } }", src, flags=re.S) return src def main(): import os # 幂等保护 d = read(os.path.join(ROOT, "MainForm.Designer.cs")) if "ribbonStrip1" in d: print("Designer.cs 已含 ribbonStrip1,跳过") else: write(os.path.join(ROOT, "MainForm.Designer.cs"), replace_designer(d)) print("Designer.cs 改写完成") m = read(os.path.join(ROOT, "MainForm.cs")) if "ribbonStrip1_ButtonClick(object sender" not in m: m2 = replace_mainform_cs(m) m2 = add_handlers(m2) write(os.path.join(ROOT, "MainForm.cs"), m2) print("MainForm.cs 改写完成") else: print("MainForm.cs 已改,跳过") z = read(os.path.join(ROOT, "主窗口.cs")) if "FindRibbonButton(\"button10\")" not in z: write(os.path.join(ROOT, "主窗口.cs"), replace_zhuwindow(z)) print("主窗口.cs 改写完成") else: print("主窗口.cs 已改,跳过") c = read(os.path.join(ROOT, "MainForm.旧页签兼容.cs")) if "tabPage2 { get" in c: write(os.path.join(ROOT, "MainForm.旧页签兼容.cs"), replace_compat(c)) print("旧页签兼容.cs 改写完成") else: print("旧页签兼容.cs 已改,跳过") if __name__ == "__main__": main()