942. DI String Match

本文深入解析了一种基于字符串I和D的排列算法,该算法能够生成符合特定递增和递减规则的整数序列。通过实例演示了算法的工作原理,包括其核心逻辑和证明过程,同时探讨了可能的解空间和算法的必要条件。

Given a string S that only contains "I" (increase) or "D" (decrease), let N = S.length.

Return any permutation A of [0, 1, ..., N] such that for all i = 0, ..., N-1:

  • If S[i] == "I", then A[i] < A[i+1]
  • If S[i] == "D", then A[i] > A[i+1]

 

Example 1:

Input: "IDID"
Output: [0,4,1,3,2]

Example 2:

Input: "III"
Output: [0,1,2,3]

Example 3:

Input: "DDI"
Output: [3,2,0,1]

 

Note:

  1. 1 <= S.length <= 10000
  2. S only contains characters "I" or "D".

 

 

题解:可以负责任的告诉大家,这道题虽然列为简单题,但是绝不简单。

下面介绍第一种解法:

class Solution {
    public int[] diStringMatch(String S) {
        int Slength = S.length();
        int decr = Slength;
        int incr = 0;
        int[] a = new int[Slength+1];
        for(int i=0;i<Slength;i++){
           if(S.charAt(i)=='I')
               a[i] = incr++;
            else
               a[i] = decr--;
        }
        a[Slength] = incr;
        return a;
    }
}

证明:

只需要证明,对于任何 > 或者 < , 算法的规则都能满足。

incr = 0; decr = S.length;

△N = decr-incr; 由于每次遇到一个符号,△N-1。

当符号为“ <   <   <   <   < ”: decr--可以保证符号的正确性。

当符号为“ >   >   >    >   >”: incr++可以保住符号的正确性。

当符号为“ ……<   >   <   >   <……":  任意时刻decr和incr开始比较,那么任意时刻是否满足 incr < decr ?

答案是:YES! 由于符号的数量为N,最开始△N = N。由于至少出现一对 < >, min(△N)= 1,仍然满足incr < decr;

综上,得证。

其他可能解法:

第一种解法的前提是:小于号左边的数字  全部都小于小于号右边的数字。根据之前的分析这样可以求出一个解。

"IDIDIDDDIIIID"

Output

[0,13,1,12,2,11,10,9,3,4,5,6,8,7]

Expected

[0,13,1,12,2,11,10,9,3,4,5,6,8,7]

小于号左边【0,1,2,3,4,5,6】 大于号右边【7,8,9 ,10,11,12,13】

0< 13 > 1 < 12 > 2 < 11 > 10 > 9 > 3 < 4 < 5 < 6 < 8 > 7

0< 13 > 9 < 12 > 2 < 11 > 10 > 3 > 1 < 4 < 5 < 6 < 8 > 7

我们将小于号和大于号的集合里面的数字进行交换,并做适当调整,发现可以满足要求。

那么,问题来了,第一种解法的前提可以保证得出一个解,但是不是必要条件!那么求解这个问题的必要条件是什么?

换句话说,如何求出满足条件的所有解?个人认为是一件非常困难的事情。

 

package com.ruoyi.kettle.config; import com.ruoyi.kettle.tools.KettleUtil; import lombok.extern.slf4j.Slf4j; import org.pentaho.di.core.Const; import org.pentaho.di.core.KettleEnvironment; import org.pentaho.di.core.exception.KettleException; import org.pentaho.di.core.plugins.PluginFolder; import org.pentaho.di.core.plugins.StepPluginType; import org.pentaho.di.core.util.EnvUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.net.URISyntaxException; import java.net.URL; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; import java.util.Enumeration; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.jar.JarEntry; import java.util.jar.JarFile; @Slf4j public class KettleEnv { private static final String PLUGIN_DIR = "kettlePlugins"; private static final String JNDI_DIR = "simple-jndi"; private static volatile Path extractedPluginPath; private static volatile Path extractedJndiPath; private static String pluginBasePath; // 读写锁确保线程安全 private static final ReentrantReadWriteLock jndiLock = new ReentrantReadWriteLock(); public static synchronized void init() { try { String pluginPath = getConfiguredPluginPath(); if (pluginPath == null) { // 自动检测并处理插件目录 pluginPath = resolvePluginPath(); } log.info("使用的Kettle插件路径: {}", pluginPath); // 添加插件路径(避免重复添加) String finalPluginPath = pluginPath; if (StepPluginType.getInstance().getPluginFolders().stream() .noneMatch(a -> a.getFolder().equals(finalPluginPath))) { StepPluginType.getInstance().getPluginFolders().add( new PluginFolder(pluginPath, false, true) ); } // 初始化Kettle环境 KettleEnvironment.init(); EnvUtil.environmentInit(); log.info("Kettle环境初始化成功"); pluginBasePath = pluginPath; } catch (Exception e) { log.error("Kettle环境初始化失败", e); } } /** * 设置JNDI环境(任务运行前调用) */ public static void setupJndiEnvironment() { jndiLock.writeLock().lock(); try { Path jndiPath = getDefaultJndiPath(); // 确保目录存在 if (!Files.exists(jndiPath)) { Files.createDirectories(jndiPath); log.info("创建JNDI目录: {}", jndiPath); } // 设置JNDI系统属性 System.setProperty("org.osjava.sj.root", jndiPath.toString()); System.setProperty("org.osjava.sj.delimiter", "/"); System.setProperty("org.osjava.sj.reload", "true"); Const.JNDI_DIRECTORY = jndiPath.toString(); log.info("JNDI路径已设置: {}", jndiPath); } catch (Exception e) { log.error("JNDI环境设置失败", e); throw new RuntimeException(e); } finally { jndiLock.writeLock().unlock(); } } /** * 获取默认JNDI路径 */ public static Path getDefaultJndiPath() { // 优先使用已提取的JNDI路径 if (extractedJndiPath != null) { return extractedJndiPath; } // 检查是否有配置的外部JNDI路径 String externalJndiPath = System.getProperty("kettle.jndi.path"); if (externalJndiPath != null && Files.exists(Paths.get(externalJndiPath))) { return Paths.get(externalJndiPath); } // 默认使用项目根目录下的config/simple-jndi return Paths.get(System.getProperty("user.dir"), "config/simple-jndi"); } /** * 读取jdbc.properties文件内容为字符串(保留原始格式) */ public static String readJdbcPropertiesAsString() throws IOException { return readJdbcPropertiesAsString(getDefaultJndiPath()); } public static String readJdbcPropertiesAsString(Path jndiPath) throws IOException { jndiLock.readLock().lock(); try { Path jdbcFile = jndiPath.resolve("jdbc.properties"); if (!Files.exists(jdbcFile)) { log.warn("jdbc.properties文件不存在: {}", jdbcFile); return ""; } return new String(Files.readAllBytes(jdbcFile), StandardCharsets.UTF_8); } finally { jndiLock.readLock().unlock(); } } /** * 将字符串内容写入jdbc.properties文件(保留原始格式) */ public static void writeJdbcPropertiesFromString(String content) throws IOException { writeJdbcPropertiesFromString(getDefaultJndiPath(), content); } public static void writeJdbcPropertiesFromString(Path jndiPath, String content) throws IOException { jndiLock.writeLock().lock(); try { Path jdbcFile = jndiPath.resolve("jdbc.properties"); // 确保目录存在 if (!Files.exists(jndiPath)) { Files.createDirectories(jndiPath); } Files.write(jdbcFile, content.getBytes(StandardCharsets.UTF_8)); log.info("jdbc.properties更新成功, 路径: {}", jdbcFile); } finally { jndiLock.writeLock().unlock(); } } public static String getPluginBasePath() { return pluginBasePath; } /** * 获取配置的插件路径(外部目录优先) */ public static String getConfiguredPluginPath() { // 1. 检查系统属性 String sysPropPath = System.getProperty("kettle.plugin.path"); if (sysPropPath != null && Files.exists(Paths.get(sysPropPath))) { return sysPropPath; } // 2. 检查当前工作目录下的插件目录 Path workingDirPath = Paths.get(System.getProperty("user.dir"), PLUGIN_DIR); if (Files.exists(workingDirPath)) { return workingDirPath.toString(); } // 3. 检查JAR文件同级的插件目录 Path jarDirPath = null; try { jarDirPath = Paths.get(KettleUtil.class.getProtectionDomain() .getCodeSource().getLocation().toURI()) .getParent() .resolve(PLUGIN_DIR); } catch (URISyntaxException e) { throw new RuntimeException(e); } if (Files.exists(jarDirPath)) { return jarDirPath.toString(); } return null; } /** * 解析插件路径(支持JAR包和IDE环境) */ private static String resolvePluginPath() throws Exception { // 优先返回已提取的路径(避免重复提取) if (extractedPluginPath != null) { return extractedPluginPath.toString(); } URL resourceUrl = KettleUtil.class.getClassLoader().getResource(PLUGIN_DIR); if (resourceUrl == null) { throw new FileNotFoundException("未找到Kettle插件资源目录"); } // 开发环境直接使用路径 if (!"jar".equals(resourceUrl.getProtocol())) { // 同时提取JNDI目录 extractJndiFromResources(); return Paths.get(resourceUrl.toURI()).toString(); } // 生产环境提取到临时目录 synchronized (KettleEnv.class) { if (extractedPluginPath == null) { extractedPluginPath = extractPluginsFromJar(resourceUrl); // 同时提取JNDI目录 extractJndiFromJar(); } return extractedPluginPath.toString(); } } /** * 从JAR包提取插件到临时目录(优化版) */ private static Path extractPluginsFromJar(URL jarResourceUrl) throws Exception { // 创建临时目录(带随机后缀) Path tempDir = Files.createTempDirectory("kettle-plugins-"); tempDir.toFile().deleteOnExit(); log.info("创建临时插件目录: {}", tempDir); // 解析JAR文件路径 String jarPath = jarResourceUrl.getPath().split("!")[0].replace("file:", ""); File jarFile = new File(jarPath); try (JarFile jar = new JarFile(jarFile)) { Enumeration<JarEntry> entries = jar.entries(); while (entries.hasMoreElements()) { JarEntry entry = entries.nextElement(); String entryName = entry.getName(); // 只处理插件目录下的文件 if (entryName.startsWith(PLUGIN_DIR + "/") && !entry.isDirectory()) { // 计算目标路径(去掉插件目录前缀) String relativePath = entryName.substring(PLUGIN_DIR.length() + 1); Path targetPath = tempDir.resolve(relativePath); // 创建父目录 Files.createDirectories(targetPath.getParent()); // 复制文件内容 try (InputStream in = jar.getInputStream(entry)) { Files.copy(in, targetPath, StandardCopyOption.REPLACE_EXISTING); log.debug("提取插件文件: {} -> {}", entryName, targetPath); } } } } log.info("成功提取 {} 个插件文件到临时目录", Files.list(tempDir).count()); return tempDir; } /** * 从JAR包提取JNDI配置到临时目录 */ private static void extractJndiFromJar() throws Exception { URL jndiResourceUrl = KettleUtil.class.getClassLoader().getResource(JNDI_DIR); if (jndiResourceUrl == null) { log.warn("未找到JNDI资源目录"); return; } // 创建临时目录(带随机后缀) Path tempDir = Files.createTempDirectory("kettle-jndi-"); tempDir.toFile().deleteOnExit(); log.info("创建临时JNDI目录: {}", tempDir); // 解析JAR文件路径 String jarPath = jndiResourceUrl.getPath().split("!")[0].replace("file:", ""); File jarFile = new File(jarPath); try (JarFile jar = new JarFile(jarFile)) { Enumeration<JarEntry> entries = jar.entries(); while (entries.hasMoreElements()) { JarEntry entry = entries.nextElement(); String entryName = entry.getName(); // 只处理JNDI目录下的文件 if (entryName.startsWith(JNDI_DIR + "/") && !entry.isDirectory()) { // 计算目标路径(去掉JNDI目录前缀) String relativePath = entryName.substring(JNDI_DIR.length() + 1); Path targetPath = tempDir.resolve(relativePath); // 创建父目录 Files.createDirectories(targetPath.getParent()); // 复制文件内容 try (InputStream in = jar.getInputStream(entry)) { Files.copy(in, targetPath, StandardCopyOption.REPLACE_EXISTING); log.debug("提取JNDI文件: {} -> {}", entryName, targetPath); } } } } extractedJndiPath = tempDir; log.info("成功提取JNDI配置到临时目录: {}", tempDir); } /** * 在开发环境中提取JNDI配置 */ private static void extractJndiFromResources() throws Exception { URL jndiResourceUrl = KettleUtil.class.getClassLoader().getResource(JNDI_DIR); if (jndiResourceUrl == null) { log.warn("未找到JNDI资源目录"); return; } // 开发环境直接使用资源路径 extractedJndiPath = Paths.get(jndiResourceUrl.toURI()); log.info("使用开发环境JNDI目录: {}", extractedJndiPath); } /** * 重新加载Kettle环境(包括JNDI配置) */ public static synchronized void reload() { try { // 停止所有正在运行的作业 KettleJobManager.stopAllJobs(); // 1. 关闭当前Kettle环境 KettleEnvironment.shutdown(); log.info("Kettle环境已关闭"); // 3. 重新初始化 init(); log.info("Kettle环境重新初始化完成"); } catch (Exception e) { log.error("Kettle环境重新加载失败", e); throw new RuntimeException(e); } } } // 保存配置内容(保留原始格式) @PostMapping("/saveConfig") @ResponseBody public AjaxResult saveConfig(@RequestParam String content) { try { // 直接保存原始内容,不解析为Properties KettleEnv.writeJdbcPropertiesFromString(content); // 重新加载Kettle环境 KettleEnv.reload(); return success("配置保存成功"); } catch (Exception e) { return error("保存配置失败: " + e.getMessage()); } } 保存配置时把原文件也修改 ruoyi-admin/src/main/resources/simple-jndi/jdbc.properties ruoyi-admin/target/classes/simple-jndi/jdbc.properties
09-17
using System; using System.Collections.Generic; using System.Text.RegularExpressions; using System.Windows.Forms; using WindowsFormsApp1; namespace ScopeCore.Controls { public partial class PopupConditionRule : PopupServiceBase { private List<string> variableList = new List<string>(); private string assembledRule = ""; public event EventHandler<string> RuleChanged; public PopupConditionRule() { InitializeComponent(); flpConditions.AutoScroll = true; btnAddCondition.Click += BtnAddCondition_Click; btnConfirm.Click += BtnConfirm_Click; btnCancel.Click += BtnCancel_Click; tbDuration.TextChanged += TbDuration_TextChanged; // 初始至少一行 AddConditionRow(); } public void SetVariables(List<string> vars) { variableList = vars ?? new List<string>(); // 将已有行更新变量列表 foreach (Control c in flpConditions.Controls) { ConditionRowControl row = c as ConditionRowControl; if (row != null) row.SetVariableList(variableList); } } public void SetRule(string rule) { if (string.IsNullOrEmpty(rule)) { // 清空,保留一行 flpConditions.Controls.Clear(); AddConditionRow(); assembledRule = ""; return; } // 解析原始规则,拆出原子比较与逻辑符 List<string> atomics = new List<string>(); List<string> logics = new List<string>(); // 正则提取所有形如 "( ... op ... )" 的原子条件(最小括号级) // 这里假定每个原子比较都被括号包裹,例如: ( /IO/... == Shuttered ) Regex atomRegex = new Regex(@"\(\s*([^()]+?\s*(==|!=|<=|>=|<|>)\s*[^()]+?)\s*\)"); MatchCollection matches = atomRegex.Matches(rule); foreach (Match m in matches) { atomics.Add(m.Groups[1].Value.Trim()); } // 提取 atomics 之间的逻辑操作符顺序(扫描原字符串,查找 && 或 ||) // 找到每个原子在字符串中的位置,然后在两个原子之间搜索逻辑符 int idx = 0; for (int i = 0; i < atomics.Count; i++) { // find position of this atomic (first occurrence after idx) string atomicPattern = @"\(\s*" + Regex.Escape(atomics[i]) + @"\s*\)"; Match m = Regex.Match(rule, atomicPattern); if (m.Success) { idx = m.Index + m.Length; // look ahead for next logic if there is next atomic if (i + 1 < atomics.Count) { // search between end of this atomic and start of next atomic string nextAtomicPattern = @"\(\s*" + Regex.Escape(atomics[i + 1]) + @"\s*\)"; Match nextM = Regex.Match(rule, nextAtomicPattern); if (nextM.Success && nextM.Index > idx) { string between = rule.Substring(idx, nextM.Index - idx); // find first && or || Match logicM = Regex.Match(between, @"(&&|\|\|)"); if (logicM.Success) logics.Add(logicM.Value); else logics.Add("&&"); // default } else { logics.Add("&&"); } } } } // 清空当前行,逐个生成条件行 flpConditions.Controls.Clear(); for (int i = 0; i < atomics.Count; i++) { // atomics[i] 形如 "VarName == Value" string atomic = atomics[i]; // 解析 variable, operator, value Regex parts = new Regex(@"^\s*([^=<>!\s]+?)\s*(==|!=|<=|>=|<|>)\s*(.+)\s*$"); Match pm = parts.Match(atomic); string var = "", op = "==", val = ""; if (pm.Success) { var = pm.Groups[1].Value.Trim(); op = pm.Groups[2].Value.Trim(); val = pm.Groups[3].Value.Trim(); } ConditionRowControl row = CreateConditionRow(); row.SetVariableList(variableList); string logic = (i < logics.Count) ? logics[i] : "&&"; row.SetCondition(var, op, val, logic); flpConditions.Controls.Add(row); } if (atomics.Count == 0) { // 解析失败或空:保留一行 AddConditionRow(); } UpdateLogicVisibility(); RebuildRuleAndRaiseEvent(); } private void TbDuration_TextChanged(object sender, EventArgs e) { // 基本校验:非空且为非负整数 string txt = tbDuration.Text.Trim(); string err = ""; if (string.IsNullOrEmpty(txt)) { err = "Duration 不能为空(毫秒)。"; } else { int v; if (!int.TryParse(txt, out v) || v < 0) { err = "Duration 必须为非负整数(毫秒)。"; } } errorProvider1.SetError(tbDuration, err); } private void BtnAddCondition_Click(object sender, EventArgs e) { AddConditionRow(); } private void AddConditionRow() { ConditionRowControl row = CreateConditionRow(); row.SetVariableList(variableList); flpConditions.Controls.Add(row); UpdateLogicVisibility(); RebuildRuleAndRaiseEvent(); } private ConditionRowControl CreateConditionRow() { ConditionRowControl row = new ConditionRowControl(); row.DeleteClicked += (s, e) => { flpConditions.Controls.Remove(row); UpdateLogicVisibility(); RebuildRuleAndRaiseEvent(); }; row.ValueChanged += (s, e) => { RebuildRuleAndRaiseEvent(); }; return row; } private void UpdateLogicVisibility() { // 所有行的 Logic 可见,但最后一行隐藏 Logic for (int i = 0; i < flpConditions.Controls.Count; i++) { ConditionRowControl row = flpConditions.Controls[i] as ConditionRowControl; if (row != null) { row.SetLogicVisible(i != flpConditions.Controls.Count - 1); } } } private void BtnConfirm_Click(object sender, EventArgs e) { // 验证每行 value 非空 foreach (Control c in flpConditions.Controls) { ConditionRowControl row = c as ConditionRowControl; if (row != null) { string val = row.GetValue(); if (string.IsNullOrEmpty(val)) { MessageBox.Show("每行的 Value 不允许为空,请填写。", "输入错误", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } // 对数值类型可以额外验证范围 var desc = DataManager.GetIns().GetItemValue(row.GetVariable()); if (desc is DataManager.DoubleInfo) { double v; if (!double.TryParse(val, out v)) { MessageBox.Show("数值格式错误,请输入合法数字。", "输入错误", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } DataManager.DoubleInfo di = (DataManager.DoubleInfo)desc; if (v < di.Min || v > di.Max) { MessageBox.Show(string.Format("数值超出范围 {0} - {1}。", di.Min, di.Max), "输入错误", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } } } } // Duration 验证 string durText = tbDuration.Text.Trim(); if (!string.IsNullOrEmpty(durText)) { int dv; if (!int.TryParse(durText, out dv) || dv < 0) { MessageBox.Show("Duration 必须为非负整数(毫秒)。", "输入错误", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } } // 组装字符串 assembledRule = BuildRuleString(); this.DialogResult = DialogResult.OK; this.Close(); } private void BtnCancel_Click(object sender, EventArgs e) { this.DialogResult = DialogResult.Cancel; this.Close(); } private string BuildRuleString() { // 将每个原子包成 (var op val),并用逻辑符将它们连接起来,用额外 () 包裹整体,并在末尾追加 Duration(ms)(如果有) List<string> parts = new List<string>(); for (int i = 0; i < flpConditions.Controls.Count; i++) { ConditionRowControl row = flpConditions.Controls[i] as ConditionRowControl; if (row != null) { string var = row.GetVariable(); string op = row.GetOperator(); string val = row.GetValue(); parts.Add("(" + var + " " + op + " " + val + ")"); } } // 连接时每两个项之间用对应行的 Logic(第 i 项与第 i+1 项之间使用第 i 项的 Logic) if (parts.Count == 0) return ""; string joined = parts[0]; for (int i = 0; i < parts.Count - 1; i++) { ConditionRowControl row = flpConditions.Controls[i] as ConditionRowControl; string logic = (row != null) ? row.GetLogic() : "&&"; joined = "(" + joined + logic + parts[i + 1] + ")"; } // 末尾 Duration string durText = tbDuration.Text.Trim(); if (!string.IsNullOrEmpty(durText)) { joined = joined + " " + durText + "(ms)"; } return joined; } private void RebuildRuleAndRaiseEvent() { string ru = BuildRuleString(); assembledRule = ru; RuleChanged?.Invoke(this, assembledRule); } public string GetRule() { return assembledRule; } } } ConditionRowControl.cs using System; using System.Collections.Generic; using System.Windows.Forms; namespace ScopeCore.Controls { public partial class ConditionRowControl : UserControl { public event EventHandler DeleteClicked; public event EventHandler ValueChanged; public ConditionRowControl() { InitializeComponent(); // 操作符 cbOperator.Items.AddRange(new object[] { "==", "!=", "<", "<=", ">", ">=" }); cbLogic.Items.AddRange(new object[] { "&&", "||" }); cbVariable.SelectedIndexChanged += cbVariable_SelectedIndexChanged; cbOperator.SelectedIndexChanged += (s, e) => OnValueChanged(); cbLogic.SelectedIndexChanged += (s, e) => OnValueChanged(); btnDelete.Click += (s, e) => DeleteClicked?.Invoke(this, EventArgs.Empty); } public void SetVariableList(List<string> vars) { cbVariable.Items.Clear(); foreach (string v in vars) cbVariable.Items.Add(v); if (cbVariable.Items.Count > 0 && cbVariable.SelectedIndex < 0) cbVariable.SelectedIndex = 0; } public void SetCondition(string variable, string oper, string value, string logic) { if (!string.IsNullOrEmpty(variable) && cbVariable.Items.Contains(variable)) cbVariable.SelectedItem = variable; else if (cbVariable.Items.Count > 0) cbVariable.SelectedIndex = 0; if (!string.IsNullOrEmpty(oper) && cbOperator.Items.Contains(oper)) cbOperator.SelectedItem = oper; else cbOperator.SelectedIndex = 0; // 触发变量切换后会设置 Value 控件类型 ApplyValueAccordingToVariable(); SetValueText(value); if (!string.IsNullOrEmpty(logic) && cbLogic.Items.Contains(logic)) cbLogic.SelectedItem = logic; else cbLogic.SelectedIndex = 0; } private void cbVariable_SelectedIndexChanged(object sender, EventArgs e) { ApplyValueAccordingToVariable(); OnValueChanged(); } private void ApplyValueAccordingToVariable() { string varName = GetVariable(); var desc = DataManager.GetIns().GetItemValue(varName); // 如果返回 string[] 则为枚举 if (desc is string[]) { // 显示 ComboBox 做为 Value if (!(valueCombo.Visible)) { valueText.Visible = false; valueCombo.Visible = true; } valueCombo.Items.Clear(); string[] opts = desc as string[]; foreach (string o in opts) valueCombo.Items.Add(o); if (valueCombo.Items.Count > 0) valueCombo.SelectedIndex = 0; } else if (desc is DataManager.DoubleInfo) { // 数值,显示 TextBox valueCombo.Visible = false; valueText.Visible = true; // 可根据 DoubleInfo.min/max 做 placeholder 或 tooltip DataManager.DoubleInfo di = (DataManager.DoubleInfo)desc; valueText.Tag = string.Format("范围 {0} - {1}", di.Min, di.Max); } else // string 类型 { valueCombo.Visible = false; valueText.Visible = true; valueText.Tag = "字符串"; } } public string GetVariable() { if (cbVariable.SelectedItem == null) return ""; return cbVariable.SelectedItem.ToString(); } public string GetOperator() { if (cbOperator.SelectedItem == null) return ""; return cbOperator.SelectedItem.ToString(); } public string GetValue() { if (valueCombo.Visible) return valueCombo.Text.Trim(); return valueText.Text.Trim(); } public string GetLogic() { if (cbLogic.SelectedItem == null) return "&&"; return cbLogic.SelectedItem.ToString(); } public void SetLogicVisible(bool visible) { cbLogic.Visible = visible; } public void SetValueText(string v) { if (valueCombo.Visible) { if (valueCombo.Items.Contains(v)) valueCombo.SelectedItem = v; else if (valueCombo.Items.Count > 0) valueCombo.SelectedIndex = 0; } else { valueText.Text = v ?? ""; } } protected void OnValueChanged() { ValueChanged?.Invoke(this, EventArgs.Empty); } } } 控件数目不是空,但是没有被显示在窗口中。
最新发布
11-18
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值