513[Medium]:Find Bottom Left Tree Value

本文介绍一种非递归方法来寻找二叉树最底层的最左侧节点的值,通过使用两个栈来记录节点及深度,确保找到的节点是最底层最左侧的。

Part1:问题描述

Given a binary tree, find the leftmost value in the last row of the tree.

Example 1:

Input:

    2
   / \
  1   3

Output:
1

Example 2: 

Input:

        1
       / \
      2   3
     /   / \
    4   5   6
       /
      7

Output:
7

Note: You may assume the tree (i.e., the given root node) is not NULL.


Part2:解题思路

题目要求的问题很简单,二叉树最左边的节点的值<=>利用深搜从左到右遍历找到的深度最深的第一个元素。递归的代码很简单,但是不好理解,所以,我采用非递归开2个stack的方式解决这个问题。

由于我们想要找到的是层数最深的最左边的元素,所以我们应该从左边的分支开始遍历并记录已经访问的节点的层数depth,并通过不断的比较得到最先到达maxDepth层的那个节点,就是我们要找的最左边的节点。

由于我用的是stack,先进后出,我们想要达到先访问左边分支的目的,就要先让右边的节点进栈。

我与遇到的一个小问题:将currentDepth压栈的时候,最开始是写的currentDepth++,导致比较的时候出现问题结果不正确,后来举了一组简单的数据进行分析发现了这个问题。

Part3:代码

我只贴了leetcode上需要的那个函数

int findBottomLeftValue(TreeNode* root) {
	int maxDepth = 0;
	int leftValue = root->val;
	
	stack<TreeNode*> node;
	stack<int> depth;
	TreeNode* currentNode;
	int currentDepth = 0;
	
	node.push(root);
	depth.push(currentDepth);
	while(!node.empty()) {
		currentNode = node.top();
		currentDepth = depth.top();
		node.pop();
		depth.pop();
		if (currentNode->right) {
			node.push(currentNode->right);
			depth.push(currentDepth + 1);
		}
		if (currentNode->left) {
			node.push(currentNode->left);
			depth.push(currentDepth + 1);
		}
		if (currentDepth > maxDepth) {
			maxDepth = currentDepth;
			leftValue = currentNode->val; 
		}
	}
	return leftValue;
} 


<template> <div class="taobao-category-page"> <!-- 淘宝顶部导航栏 --> <div class="taobao-header"> <div class="header-left"> <i class="iconfont icon-location"></i> <span>淘宝</span> </div> <div class="header-search"> <i class="iconfont icon-search"></i> <input type="text" placeholder="搜索商品"> </div> <div class="header-right"> <i class="iconfont icon-user"></i> </div> </div> <!-- 分类主内容区 --> <div class="category-main"> <div class="menu-left"> <ul> <li class="menu-item" v-for="(menu, index) in menus" :key="index" :class="{ active: index === currentIndex }" @click="clickList(index)" ref="menuList" > <p class="text">{{ menu.name }}</p> </li> </ul> </div> <div class="menu-right" ref="itemList"> <ul> <li class="cate" v-for="(menu, index1) in menus" :key="index1" > <h4 class="cate-title">{{ menu.name }}</h4> <ul class="cate-item"> <li v-for="(item, index2) in menu.children" :key="index2"> <router-link class="cate-item-wrapper" :to="{ name: 'goodslist', params: { category_id: item.id } }" > <div class="cate-item-img"> <img :src="item.picture || defaultImg" alt=""> </div> <span>{{ item.name }}</span> </router-link> </li> </ul> </li> </ul> </div> </div> </div> </template> <script setup> import { onMounted, watch, nextTick, ref, computed } from 'vue' import { getCategoryList } from '../api' import BScroll from '@better-scroll/core' // 默认图片(淘宝风格占位图) const defaultImg = 'https://img.alicdn.com/tfs/TB1NvcHaXXXXXcSaXXXXXXXXXXX-100-100.png' // 获取分类数据 const menus = ref([]) const rightLiTops = ref([]) const menuList = ref() const itemList = ref() const initLeftScroll = index => { const menu = menuList.value if (menu && menu[index]) { const el = menu[index] leftBscroll.scrollToElement(el, 300, 0, -100) } } onMounted(() => { loadCategoryList() RightHeightFix() }) let leftBscroll = null const scrollY = ref(0) let rightBscroll = null // 监听数据变化 watch(menus, () => { nextTick(() => { initBScroll() initRightHeight() }) }) const loadCategoryList = async () => { try { const data = await getCategoryList() const treeData = convertToTree(data) menus.value = treeData } catch (error) { console.error('获取分类数据失败', error) } } // 数据转换为树形结构 const convertToTree = data => { const treeData = [] const map = {} for (const item of data) { map[item.id] = { ...item, children: [] } } for (const item of data) { const node = map[item.id] if (item.pid === 0) { treeData.push(node) } else { const parent = map[item.pid] parent.children.push(node) } } return treeData } // 点击左侧分类 const clickList = index => { scrollY.value = rightLiTops.value[index] rightBscroll.scrollTo(0, -scrollY.value) } // 初始化右侧高度 const initRightHeight = () => { const itemArray = [] let top = 0 itemArray.push(top) const allList = itemList.value?.getElementsByClassName('cate') if (allList) { Array.prototype.slice.call(allList).forEach(li => { top += li.clientHeight itemArray.push(top) }) rightLiTops.value = itemArray rightBscroll.on('scroll', pos => { scrollY.value = Math.abs(pos.y) }) } } // 初始化滚动 const initBScroll = () => { if (leftBscroll) leftBscroll.destroy() if (rightBscroll) rightBscroll.destroy() leftBscroll = new BScroll('.menu-left', { click: true, mouseWheel: true, scrollX: false, scrollY: true, bounce: false, probeType: 3 }) rightBscroll = new BScroll('.menu-right', { click: true, mouseWheel: true, probeType: 3 }) } const RightHeightFix = () => { const bottom = itemList.value?.getElementsByClassName('cate-bottom')[0] if (bottom) { bottom.style.height = '50px' // 淘宝底部固定高度 } } // 当前激活的分类索引 const currentIndex = computed(() => { const index = rightLiTops.value.findIndex((top, idx) => { if (idx === rightLiTops.value.length - 2) return true return scrollY.value >= top && scrollY.value < rightLiTops.value[idx + 1] }) if (index >= 0) initLeftScroll(index) return index }) </script> <style lang="less" scoped> /* 淘宝风格颜色变量 */ @taobao-orange: #FF4400; @taobao-light-orange: #FF7E00; @taobao-bg-gray: #F5F5F5; @taobao-text-dark: #333; @taobao-text-medium: #666; @taobao-text-light: #999; @taobao-white: #FFFFFF; /* 重置样式 */ ul, li { margin: 0; padding: 0; list-style: none; } .taobao-category-page { position: relative; width: 100%; height: 100vh; background-color: @taobao-bg-gray; overflow: hidden; /* 淘宝顶部导航栏 */ .taobao-header { display: flex; align-items: center; justify-content: space-between; height: 44px; background-color: @taobao-orange; padding: 0 10px; position: relative; z-index: 100; .header-left, .header-right { color: @taobao-white; font-size: 14px; } .header-search { flex: 1; margin: 0 10px; height: 30px; background-color: @taobao-white; border-radius: 15px; display: flex; align-items: center; padding: 0 10px; .iconfont { color: @taobao-text-light; margin-right: 5px; } input { flex: 1; border: none; outline: none; font-size: 14px; color: @taobao-text-medium; background-color: transparent; } } } /* 分类主内容区 */ .category-main { display: flex; position: absolute; top: 44px; bottom: 0; width: 100%; .menu-left { flex: 0 0 80px; width: 80px; background: @taobao-white; border-right: 1px solid #E1E1E1; .menu-item { height: 54px; width: 100%; border-bottom: 1px solid #F5F5F5; display: flex; align-items: center; justify-content: center; .text { font-size: 14px; color: @taobao-text-medium; } } .active { background-color: @taobao-bg-gray; .text { color: @taobao-orange; font-weight: 500; } } } .menu-right { flex: 1; background: @taobao-white; overflow: hidden; .cate { .cate-title { margin: 0; text-align: left; font-size: 14px; color: @taobao-text-dark; font-weight: bold; padding: 10px; background-color: @taobao-bg-gray; } .cate-item { padding: 10px; display: flex; flex-flow: row wrap; li { width: 33.333%; display: flex; flex-direction: column; align-items: center; margin-bottom: 15px; .cate-item-wrapper { display: flex; flex-direction: column; align-items: center; width: 100%; .cate-item-img { width: 60px; height: 60px; border-radius: 8px; overflow: hidden; margin-bottom: 5px; box-shadow: 0 2px 8px rgba(0,0,0,0.05); img { width: 100%; height: 100%; object-fit: cover; } } span { font-size: 12px; color: @taobao-text-medium; text-align: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; width: 100%; } } } } } } } } </style>帮我对这个分类页面进行调整,使他和原来不一样·,东西可以少一点,我需要完整的代码
06-19
import os import tkinter as tk from tkinter import ttk, filedialog, messagebox import csv import klayout.db as pya class CSVProcessor: def __init__(self): self.header = [ "#chip_x_microns", "#chip_y_microns", "#output_file_name", "#top_cell_name" ] def validate_csv(self, filepath): """验证CSV文件格式是否正确""" try: with open(filepath, 'r', encoding='utf-8') as f: reader = csv.reader(f) actual_header = [col.strip() for col in next(reader)] expected_header = [col.strip() for col in self.header] if actual_header != expected_header: raise ValueError( f"CSV header mismatch.\n" f"Expected: {self.header}\n" f"Got: {actual_header}\n" f"Note: Please remove trailing spaces in the CSV header" ) for row_num, row in enumerate(reader, 2): if len(row) != 4: raise ValueError(f"Row {row_num} has incorrect number of columns") try: float(row[0]), float(row[1]) except ValueError: raise ValueError(f"Row {row_num} contains non-numeric values in x/y columns") return True except Exception as e: print("CSV Validation Error", str(e)) return False def process_csv(self, csv_path): """处理CSV文件并返回参数列表""" params_list = [] with open(csv_path, 'r', encoding='utf-8') as f: reader = csv.reader(f) next(reader) for row in reader: if not row: continue params = { 'chip_x_microns': float(row[0]), 'chip_y_microns': float(row[1]), 'output_file_name': row[2].strip(), 'top_cell_name': row[3].strip(), } params_list.append(params) return params_list class RopeOptimizer: def __init__(self, lengths, target_length): self.lengths = lengths self.lengths.sort(reverse=True) self.target_length = target_length def optimize_rope_lengths(self): rope_counts = {length: 0 for length in self.lengths} remaining_length = self.target_length for length in self.lengths: max_count = int(remaining_length // length) rope_counts[length] = max_count remaining_length -= max_count * length if remaining_length: rope_counts[self.lengths[-1]] += 1 remaining_length -= self.lengths[-1] return rope_counts, int(remaining_length) class LayoutPattern: def __init__(self, filename): self.layout_name = filename self.lay = None def find_cell(self, name): return self.lay.cell(name) def size_get(self, cell): bbox = cell.bbox() if bbox.empty(): return 0, 0, pya.Box(left=0, bottom=0, right=0, top=0) width = bbox.right - bbox.left height = bbox.top - bbox.bottom return width, height, bbox def size_get_with_cell_name(self, cell_name): cell = self.find_cell(cell_name) return self.size_get(cell) def dbu_get(self): return self.lay.dbu def destroy(self): self.lay._destroy() class LayoutReader(LayoutPattern): def __init__(self, filename): super().__init__(filename) self.lay = pya.Layout(editable=False) self.lay.read(filename) class LayoutWriter(LayoutPattern): def __init__(self, filename): super().__init__(filename) self.lay = pya.Layout(editable=True) def create_cell(self, cell_name): return self.lay.create_cell(cell_name) def delete_cell(self, cell): cell.delete() def instance_to(self, cell, x, y): pass def dbu_set(self, dbu_val): self.lay.dbu = dbu_val def make_stream(self): self.lay.write(self.layout_name) def flatten(self, cell_name): cell = self.find_cell(cell_name) cell.flatten(-1, True) def flatten_cell(self, cell): cell.flatten(-1, True) def run_fsr(in_file, out_file, chip_x_microns, chip_y_microns, input_corner_cell="cell_corner", input_line_cell_longest="cell_1", input_line_cell_medium="cell_2", input_line_cell_shortest="cell_3", output_topcell="top"): pattern = LayoutReader(in_file) corner_cell = pattern.find_cell(input_corner_cell) if corner_cell is None: print(f"ERROR: Cell {input_corner_cell} not found in {in_file}.") return False line10_cell = pattern.find_cell(input_line_cell_longest) if line10_cell is None: print(f"ERROR: Cell {input_line_cell_longest} not found in {in_file}.") return False line1_cell = pattern.find_cell(input_line_cell_medium) if line1_cell is None: print(f"ERROR: Cell {input_line_cell_medium} not found in {in_file}.") return False line0d1_cell = pattern.find_cell(input_line_cell_shortest) if line0d1_cell is None: print(f"ERROR: Cell {input_line_cell_shortest} not found in {in_file}.") return False sr = LayoutWriter(out_file) sr.dbu_set(pattern.dbu_get()) sr_corner_cell = sr.create_cell(cell_name=input_corner_cell) sr_line10_cell = sr.create_cell(cell_name=input_line_cell_longest) sr_line1_cell = sr.create_cell(cell_name=input_line_cell_medium) sr_line0d1_cell = sr.create_cell(cell_name=input_line_cell_shortest) sr_corner_cell.copy_tree(corner_cell) sr_line10_cell.copy_tree(line10_cell) sr_line1_cell.copy_tree(line1_cell) sr_line0d1_cell.copy_tree(line0d1_cell) sr.flatten_cell(sr_corner_cell) sr.flatten_cell(sr_line10_cell) sr.flatten_cell(sr_line1_cell) sr.flatten_cell(sr_line0d1_cell) _, _, bbox_corner = sr.size_get(sr_corner_cell) _, _, bbox_line10 = sr.size_get(sr_line10_cell) _, _, bbox_line1 = sr.size_get(sr_line1_cell) _, _, bbox_line0d1 = sr.size_get(sr_line0d1_cell) sr_corner_cell.transform(pya.Trans(pya.Trans.R0, x=-bbox_corner.left, y=-bbox_corner.bottom)) sr_line10_cell.transform(pya.Trans(pya.Trans.R0, x=-bbox_line10.left, y=-bbox_line10.bottom)) sr_line1_cell.transform(pya.Trans(pya.Trans.R0, x=-bbox_line1.left, y=-bbox_line1.bottom)) sr_line0d1_cell.transform(pya.Trans(pya.Trans.R0, x=-bbox_line0d1.left, y=-bbox_line0d1.bottom)) width_corner, height_corner, bbox_corner = sr.size_get(sr_corner_cell) width_line10, height_line10, bbox_line10 = sr.size_get(sr_line10_cell) width_line1, height_line1, bbox_line1 = sr.size_get(sr_line1_cell) width_line0d1, height_line0d1, bbox_line0d1 = sr.size_get(sr_line0d1_cell) if not (height_line10 == height_line1 == height_line0d1): print( f"ERROR: heights of cell {input_line_cell_longest}, {input_line_cell_medium} and {input_line_cell_shortest} \ are not equal, check {in_file} for details.") return False lengths = [ width_line10, width_line1, width_line0d1 ] floating_len = width_corner + height_corner - 2 * height_line10 target_length_x = round(float(chip_x_microns) / pattern.dbu_get()) - floating_len optimizer_x = RopeOptimizer(lengths, target_length_x) result_x, error_x = optimizer_x.optimize_rope_lengths() target_length_y = round(float(chip_y_microns) / pattern.dbu_get()) - floating_len optimizer_y = RopeOptimizer(lengths, target_length_y) result_y, error_y = optimizer_y.optimize_rope_lengths() pattern.destroy() sr_lines = [sr_line10_cell, sr_line1_cell, sr_line0d1_cell] sr_linex_cell = sr.create_cell("linex") sr_liney_cell = sr.create_cell("liney") for item, line in zip(lengths, sr_lines): _, _, linex_bbox = sr.size_get_with_cell_name("linex") widthx, heightx, _ = sr.size_get(line) _, _, liney_bbox = sr.size_get_with_cell_name("liney") widthy, heighty, _ = sr.size_get(line) if result_x[item] == 0 and result_y[item] == 0: sr.delete_cell(line) continue if result_x[item] > 0: sr_linex_trans = pya.Trans(pya.Trans.R0, x=linex_bbox.right, y=linex_bbox.bottom) sr_linex_a = pya.Vector(x=widthx, y=0) sr_linex_b = pya.Vector(x=0, y=heightx) inst_array = pya.CellInstArray(line, sr_linex_trans, sr_linex_a, sr_linex_b, result_x[item], 1) sr_linex_cell.insert(inst_array) if result_y[item] > 0: sr_liney_trans = pya.Trans(x=liney_bbox.right, y=liney_bbox.bottom) sr_liney_a = pya.Vector(widthy, 0) sr_liney_b = pya.Vector(0, heighty) inst_array = pya.CellInstArray(line, sr_liney_trans, sr_liney_a, sr_liney_b, result_y[item], 1) sr_liney_cell.insert(inst_array) sr_top_cell = sr.create_cell(output_topcell) width_top, height_top, bbox_top = sr.size_get(sr_top_cell) inst = pya.CellInstArray(sr_corner_cell, pya.Trans(x=bbox_top.left, y=bbox_top.bottom)) sr_top_cell.insert(inst) width_top, height_top, bbox_top = sr.size_get(sr_top_cell) trans = pya.Trans(pya.Trans.R0, x=bbox_top.right, y=bbox_top.bottom) inst = pya.CellInstArray(sr_linex_cell, trans) sr_top_cell.insert(inst) width_top, height_top, bbox_top = sr.size_get(sr_top_cell) trans = pya.Trans(pya.Trans.R90, x=bbox_top.right + height_corner + error_x, y=bbox_top.bottom) inst = pya.CellInstArray(sr_corner_cell, trans) sr_top_cell.insert(inst) width_top, height_top, bbox_top = sr.size_get(sr_top_cell) trans = pya.Trans(pya.Trans.R90, x=bbox_top.right, y=bbox_top.top) inst = pya.CellInstArray(sr_liney_cell, trans) sr_top_cell.insert(inst) width_top, height_top, bbox_top = sr.size_get(sr_top_cell) trans = pya.Trans(pya.Trans.R180, x=bbox_top.right, y=bbox_top.top + height_corner + error_y) inst = pya.CellInstArray(sr_corner_cell, trans) sr_top_cell.insert(inst) width_top, height_top, bbox_top = sr.size_get(sr_top_cell) trans = pya.Trans(pya.Trans.R180, x=bbox_top.right - width_corner, y=bbox_top.top) inst = pya.CellInstArray(sr_linex_cell, trans) sr_top_cell.insert(inst) width_top, height_top, bbox_top = sr.size_get(sr_top_cell) trans = pya.Trans(pya.Trans.R270, x=bbox_top.left, y=bbox_top.top) inst = pya.CellInstArray(sr_corner_cell, trans) sr_top_cell.insert(inst) width_top, height_top, bbox_top = sr.size_get(sr_top_cell) trans = pya.Trans(pya.Trans.R270, x=bbox_top.left, y=bbox_top.top - width_corner) inst = pya.CellInstArray(sr_liney_cell, trans) sr_top_cell.insert(inst) sr.flatten(output_topcell) width_top, height_top, bbox_top = sr.size_get(sr_top_cell) BORDER_LAYER = sr.layer(259, 99) AA_box = pya.Box(0, 0, width_top, height_top) output_topcell.shapes(BORDER_LAYER).insert(AA_box) sr.make_stream() return True class DataProcessorApp: def __init__(self): # Style constants self.BG_COLOR = "#f0f0f0" self.ACCENT_COLOR = "#4a6fa5" self.TEXT_COLOR = "#333333" self.FONT = ("Segoe UI", 10) # Input variables self.x = None self.y = None self.input_gds_path = None self.input_csv_path = None self.output_file_path = None self.setup_ui() def setup_ui(self): """Initialize all UI components""" self.root = tk.Tk() self.root.title("Auto Fluid Seal Ring Tool") self.root.geometry("600x400") self.root.resizable(False, False) self.root.configure(bg=self.BG_COLOR) self.setup_styles() self.create_widgets() self.setup_layout() # Initialize UI state self.toggle_processing_mode() def setup_styles(self): """Configure ttk styles""" self.style = ttk.Style() self.style.theme_use('clam') self.style.configure('TFrame', background=self.BG_COLOR) self.style.configure('TLabel', background=self.BG_COLOR, font=self.FONT, foreground=self.TEXT_COLOR) self.style.configure('TButton', font=self.FONT, padding=5) self.style.configure('Accent.TButton', background=self.ACCENT_COLOR, foreground='white') self.style.map('Accent.TButton', background=[('active', '#3a5a8f'), ('disabled', '#a0a0a0')]) def create_widgets(self): """Create all UI widgets""" # Mode selection self.mode_frame = ttk.Frame(self.root, padding=(10, 10, 10, 5)) self.create_label(self.mode_frame, "Processing Mode:").grid(row=0, column=0, sticky="w") self.processing_mode = tk.StringVar(value="single") self.mode_buttons_frame = ttk.Frame(self.mode_frame) self.mode_buttons_frame.grid(row=0, column=1, sticky="w") ttk.Radiobutton(self.mode_buttons_frame, text="Single Mode", variable=self.processing_mode, value="single", command=self.toggle_processing_mode).pack(side="left", padx=5) ttk.Radiobutton(self.mode_buttons_frame, text="Batch Mode", variable=self.processing_mode, value="batch", command=self.toggle_processing_mode).pack(side="left", padx=5) # Configuration file (common for both modes) self.in_gds_frame = ttk.Frame(self.root, padding=(20, 10, 20, 10), relief="groove", borderwidth=1) self.create_label(self.in_gds_frame, "Input GDS File:").grid(row=0, column=0, padx=5, pady=5, sticky="e") self.entry_ingds = self.create_entry(self.in_gds_frame) self.entry_ingds.grid(row=0, column=1, padx=5, pady=5, sticky="we") self.create_button(self.in_gds_frame, "Browse...", self.select_in_gds_file).grid(row=0, column=2, padx=5, pady=5) # Single mode frame self.frame_single = ttk.Frame(self.root, padding=(20, 10, 20, 10), relief="groove", borderwidth=1) self.create_label(self.frame_single, "X(um):").grid(row=0, column=0, padx=5, pady=5, sticky="e") self.entry_x = self.create_entry(self.frame_single, width=31) self.entry_x.grid(row=0, column=1, padx=5, pady=5, sticky="we") self.create_label(self.frame_single, "Y(um):").grid(row=0, column=2, padx=5, pady=5, sticky="e") self.entry_y = self.create_entry(self.frame_single, width=31) self.entry_y.grid(row=0, column=3, padx=5, pady=5, sticky="we") # Batch mode frame self.frame_batch = ttk.Frame(self.root, padding=(20, 10, 20, 10), relief="groove", borderwidth=1) self.create_label(self.frame_batch, "Input CSV File:").grid(row=0, column=0, padx=5, pady=5, sticky="e") self.entry_batch_input = self.create_entry(self.frame_batch) self.entry_batch_input.grid(row=0, column=1, padx=5, pady=5, sticky="we") self.create_button(self.frame_batch, "Browse...", self.select_batch_input).grid(row=0, column=2, padx=5, pady=5) # Output file self.output_frame = ttk.Frame(self.root, padding=(10, 10, 10, 10)) self.create_label(self.output_frame, "Output GDS File:").grid(row=0, column=0, padx=5, pady=5, sticky="e") self.entry_output = self.create_entry(self.output_frame, width=52) self.entry_output.grid(row=0, column=1, padx=5, pady=5, sticky="we") self.create_button(self.output_frame, "Browse...", self.select_output_path).grid(row=0, column=2, padx=5, pady=5) # Run button self.button_frame = ttk.Frame(self.root, padding=(10, 10, 10, 10)) self.create_button(self.button_frame, "Run", self.run_process).grid(sticky="ew", pady=5) def setup_layout(self): """Arrange widgets in the window""" self.mode_frame.grid(row=0, column=0, columnspan=3, sticky="we") self.in_gds_frame.grid(row=1, column=0, columnspan=3, padx=10, pady=5, sticky="we") self.frame_single.grid(row=2, column=0, columnspan=3, padx=10, pady=5, sticky="nsew") self.frame_batch.grid(row=2, column=0, columnspan=3, padx=10, pady=5, sticky="nsew") self.output_frame.grid(row=3, column=0, columnspan=3, sticky="we") self.button_frame.grid(row=4, column=0, columnspan=3, sticky="we") self.root.grid_columnconfigure(0, weight=1) self.root.grid_rowconfigure(2, weight=1) def create_label(self, parent, text): """Helper to create styled labels""" return ttk.Label(parent, text=text, background=self.BG_COLOR, font=self.FONT, foreground=self.TEXT_COLOR) def create_entry(self, parent, width=50): """Helper to create styled entry fields""" return ttk.Entry(parent, font=self.FONT, width=width) def create_button(self, parent, text, command): """Helper to create styled buttons""" return ttk.Button(parent, text=text, command=command, style='Accent.TButton') def run_process(self): """Execute data processing based on selected mode""" try: # First validate the config file ingds_file = self.entry_ingds.get() if not ingds_file: messagebox.showerror("Error", "Please select input GDS file.") return self.input_gds_path = ingds_file if self.processing_mode.get() == "single": self.process_single_mode() else: self.process_batch_mode() except Exception as e: messagebox.showerror("Error", f"Processing error:\n{str(e)}") def process_single_mode(self): """Process data in single mode""" val1 = self.entry_x.get() val2 = self.entry_y.get() output_path = self.entry_output.get() if not val1 or not val2: messagebox.showerror("Error", "Please enter X and Y values.") return if not output_path: messagebox.showerror("Error", "Please select output GDS file path.") return output_dir = os.path.dirname(output_path) if output_dir: os.makedirs(output_dir, exist_ok=True) try: self.x = float(val1) self.y = float(val2) self.output_file_path = output_path except ValueError: messagebox.showerror("Error", "Please enter valid X and Y numbers.") return print(f"input GDS: {self.input_gds_path}") result = run_fsr(self.input_gds_path, self.output_file_path, self.x, self.y) print(f"size: {self.x}*{self.y}, stream out: {self.output_file_path}.") if result is True: messagebox.showinfo("Success", f"Processing complete!\nResult saved to:\n{output_path}") else: messagebox.showerror("Error", f"Processing error!\nCheck terminal output for details.\n") def process_batch_mode(self): """Process data in batch mode""" input_file = self.entry_batch_input.get() output_path = self.entry_output.get() if not input_file: messagebox.showerror("Error", "Please select input CSV file") return self.input_csv_path = input_file self.output_file_path = output_path processor = CSVProcessor() if not processor.validate_csv(self.input_csv_path): return params_list = processor.process_csv(self.input_csv_path) print(f"input GDS: {self.input_gds_path}") print(f"input CSV: {self.input_csv_path}") success_count = 0 for param in params_list: x = param.get('chip_x_microns') y = param.get('chip_y_microns') out_file = param.get('output_file_name') result = run_fsr(self.input_gds_path, out_file, x, y, output_topcell=param.get('top_cell_name')) print(f"size: {x}*{y}, stream out: {out_file}.") if result: success_count += 1 if success_count != len(params_list): messagebox.showerror("Error", f"Processing error!\nCheck terminal output for details.\n") else: messagebox.showinfo("Success", f"Processing complete!") def select_in_gds_file(self): """Open file dialog for configuration file selection""" file_path = filedialog.askopenfilename( filetypes=[ ("GDS files", "*.gds"), ("GDS files", "*.GDS"), ("All files", "*.*") ], title="Select Input GDS File" ) if file_path: self.entry_ingds.delete(0, tk.END) self.entry_ingds.insert(0, file_path) def select_output_path(self): """Open file dialog for output path selection""" try: x, y = self.entry_x.get(), self.entry_y.get() default_name = f"sealring_{x}x{y}.gds" if x and y else "" except: default_name = "" file_path = filedialog.asksaveasfilename( filetypes=[ ("GDS files", "*.gds"), ("GDS files", "*.GDS"), ("All files", "*.*") ], title="Save Output GDS File", initialfile=default_name, defaultextension=".gds" ) if file_path: self.entry_output.delete(0, tk.END) self.entry_output.insert(0, file_path) def select_batch_input(self): """Open file dialog for batch input selection""" file_path = filedialog.askopenfilename( filetypes=[ ("CSV files", "*.csv"), ("CSV files", "*.CSV"), ("All files", "*.*") ], title="Select CSV File" ) if file_path: self.entry_batch_input.delete(0, tk.END) self.entry_batch_input.insert(0, file_path) def toggle_processing_mode(self): """Switch between single and batch mode UI""" if self.processing_mode.get() == "single": self.frame_single.grid() self.frame_batch.grid_remove() self.output_frame.grid() else: self.frame_batch.grid() self.frame_single.grid_remove() self.output_frame.grid_remove() self.root.update_idletasks() self.root.geometry("") def run(self): """Start the application""" self.root.mainloop() if __name__ == "__main__": app = DataProcessorApp() app.run() 中我加了 width_top, height_top, bbox_top = sr.size_get(sr_top_cell) BORDER_LAYER = sr.layer(259, 99) AA_box = pya.Box(0, 0, width_top, height_top) output_topcell.shapes(BORDER_LAYER).insert(AA_box)这一段为什么不能运行了
最新发布
01-09
内容概要:本文系统阐述了Java Persistence API(JPA)的核心概念、技术架构、核心组件及实践应用,重点介绍了JPA作为Java官方定义的对象关系映射(ORM)规范,如何通过实体类、EntityManager、JPQL和persistence.xml配置文件实现Java对象与数据库表之间的映射与操作。文章详细说明了JPA解决的传统JDBC开发痛点,如代码冗余、对象映射繁琐、跨数据库兼容性差等问题,并解析了JPA与Hibernate、EclipseLink等实现框架的关系。同时提供了基于Hibernate和MySQL的完整实践案例,涵盖Maven依赖配置、实体类定义、CRUD操作实现等关键步骤,并列举了常用JPA注解及其用途。最后总结了JPA的标准化优势、开发效率提升能力及在Spring生态中的延伸应用。 适合人群:具备一定Java基础,熟悉基本数据库操作,工作1-3年的后端开发人员或正在学习ORM技术的中级开发者。 使用场景及目标:①理解JPA作为ORM规范的核心原理与组件协作机制;②掌握基于JPA+Hibernate进行数据库操作的开发流程;③为技术选型、团队培训或向Spring Data JPA过渡提供理论与实践基础。 阅读建议:此资源以理论结合实践的方式讲解JPA,建议读者在学习过程中同步搭建环境,动手实现文中示例代码,重点关注EntityManager的使用、JPQL语法特点以及注解配置规则,从而深入理解JPA的设计思想与工程价值。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值