AS光标切回上一次的位置

原本的快捷键是
Ctrl+Alt+←返回上一次浏览位置back
Ctrl+Alt+→返回下一次浏览位置forward

但是windows的这个快捷键被占用了,是切换屏幕的显示方向。

快速解决办法:

增加快捷键

File→settings→keymap→Main menu→Navigate→Add Keyboard Shortcut.

然后在键盘按下你想要的快捷键即可,这样就能用Ctrl+Alt+,返回back,用Ctrl+Alt+/返回forward
 

end

public class 自动补全管理器 { private List<string> lst候选词列表; private bool bl是否启用功能 = false; private ToolStripDropDown 下拉菜单; private System.Windows.Forms.ListBox lb候选词列表框; private ToolStripControlHost 控件宿主; private Word.Application appWord应用; private string str当前输入缓存 = ""; public 自动补全管理器() { fun初始化提示窗体(); } public void fun初始化(Word.Application wordApp, List<string> lst外部候选词列表 = null) { appWord应用 = wordApp; // 设置候选词列表 if (lst外部候选词列表 != null) { lst候选词列表 = lst外部候选词列表; } else { lst候选词列表 = new List<string> { "第一芯片", "第一结构件", "第二芯片", "第二结构件", "第三芯片" }; } // 注册Word事件 appWord应用.WindowSelectionChange += fun处理选择变化; appWord应用.DocumentChange += () => fun隐藏提示窗体(); } private void fun初始化提示窗体() { 下拉菜单 = new ToolStripDropDown(); 下拉菜单.AutoSize = false; 下拉菜单.Size = new System.Drawing.Size(250, 120); 下拉菜单.BackColor = System.Drawing.Color.White; 下拉菜单.Padding = new Padding(0); 下拉菜单.Margin = new Padding(0); // 设置下拉菜单的渲染样式 下拉菜单.Renderer = new ToolStripProfessionalRenderer(new 自定义颜色表()); lb候选词列表框 = new System.Windows.Forms.ListBox(); lb候选词列表框.Size = new System.Drawing.Size(250, 120); lb候选词列表框.Dock = DockStyle.Fill; lb候选词列表框.BorderStyle = System.Windows.Forms.BorderStyle.None; lb候选词列表框.Font = new System.Drawing.Font("微软雅黑", 10); lb候选词列表框.ItemHeight = 22; lb候选词列表框.BackColor = System.Drawing.Color.White; lb候选词列表框.ForeColor = System.Drawing.Color.Black; // 绑定ListBox事件 lb候选词列表框.KeyDown += fun处理列表框按键; lb候选词列表框.DoubleClick += fun处理列表框双击; lb候选词列表框.PreviewKeyDown += fun处理列表框预览按键; 控件宿主 = new ToolStripControlHost(lb候选词列表框); 控件宿主.AutoSize = false; 控件宿主.Size = new System.Drawing.Size(250, 120); 控件宿主.Margin = new Padding(0); 控件宿主.Padding = new Padding(0); 下拉菜单.Items.Add(控件宿主); } // 自定义颜色表以保持白色背景 private class 自定义颜色表 : ProfessionalColorTable { public override System.Drawing.Color ToolStripDropDownBackground { get { return System.Drawing.Color.White; } } } private void fun处理选择变化(Word.Selection sel当前选择) { if (!bl是否启用功能) return; try { // 获取当前光标前的完整单词 string str当前单词 = fun获取光标前单词(sel当前选择); System.Diagnostics.Debug.WriteLine($"处理选择变化 - 当前单词: '{str当前单词}', 缓存: '{str当前输入缓存}'"); if (!string.IsNullOrEmpty(str当前单词)) { // 只有当新单词与缓存不同时才更新 if (str当前单词 != str当前输入缓存) { str当前输入缓存 = str当前单词; System.Drawing.Point pt光标位置 = Control.MousePosition; var lst匹配的词语列表 = lst候选词列表 .Where(str词语 => str词语.StartsWith(str当前输入缓存, StringComparison.OrdinalIgnoreCase)) .ToList(); System.Diagnostics.Debug.WriteLine($"找到 {lst匹配的词语列表.Count} 个匹配项"); if (lst匹配的词语列表.Count > 0) { fun显示提示窗体(lst匹配的词语列表, pt光标位置); } else { fun隐藏提示窗体(); // 如果没有匹配项,清空缓存重新开始 str当前输入缓存 = ""; } } } else { // 如果获取不到单词,检查是否是删除操作 if (!string.IsNullOrEmpty(str当前输入缓存)) { // 可能是用户删除了内容,清空缓存 str当前输入缓存 = ""; System.Diagnostics.Debug.WriteLine("检测到删除操作,清空缓存"); } fun隐藏提示窗体(); } } catch (Exception ex异常) { System.Diagnostics.Debug.WriteLine($"处理选择变化时出错: {ex异常.Message}"); } } private string fun获取光标前单词(Word.Selection sel选择) { if (sel选择 == null) return ""; try { int 光标位置 = sel选择.Start; if (光标位置 == 0) return ""; // 从光标位置向前查找,直到遇到空格或段落开头 int 词开始位置 = 光标位置; while (词开始位置 > 0) { Word.Range 前一个字符范围 = sel选择.Document.Range(词开始位置 - 1, 词开始位置); string 前一个字符 = 前一个字符范围.Text; // 如果前一个字符为null,说明到达文档边界 if (前一个字符 == null) { break; } // 遇到空格、标点或换行就停止 if (string.IsNullOrWhiteSpace(前一个字符) || char.IsPunctuation(前一个字符[0])) { break; } 词开始位置--; } // 提取单词 Word.Range 当前词范围 = sel选择.Document.Range(词开始位置, 光标位置); string 当前词 = 当前词范围.Text; // 先不Trim // 多重空值检查 if (string.IsNullOrEmpty(当前词)) { return ""; } 当前词 = 当前词.Trim(); return 当前词.Length <= 20 ? 当前词 : ""; } catch (Exception ex) { System.Diagnostics.Debug.WriteLine($"获取光标前单词出错: {ex.Message}"); return ""; } } private void fun显示提示窗体(List<string> lst词语列表, System.Drawing.Point pt光标位置) { System.Diagnostics.Debug.WriteLine($"显示提示窗体,匹配词: {string.Join(", ", lst词语列表)}"); // 强制关闭 fun强制关闭提示窗体(); // 更新内容 lb候选词列表框.Items.Clear(); foreach (var str词语 in lst词语列表) { lb候选词列表框.Items.Add(str词语); } // 动态调整高度 int 显示行数 = Math.Min(lst词语列表.Count, 5); int 新高度 = (lb候选词列表框.ItemHeight * 显示行数) + 4; 下拉菜单.Height = 新高度; 控件宿主.Height = 新高度; if (lb候选词列表框.Items.Count > 0) { lb候选词列表框.SelectedIndex = 0; } // 显示下拉菜单 下拉菜单.Show(pt光标位置); } private void fun强制关闭提示窗体() { try { if (下拉菜单 != null) { // 尝试多种关闭方式 下拉菜单.Close(); 下拉菜单.Hide(); // 强制发送关闭消息 if (下拉菜单.IsHandleCreated) { SendMessage(下拉菜单.Handle, WM_CLOSE, IntPtr.Zero, IntPtr.Zero); } System.Windows.Forms.Application.DoEvents(); System.Threading.Thread.Sleep(20); } } catch (Exception ex) { System.Diagnostics.Debug.WriteLine($"强制关闭菜单时出错: {ex.Message}"); } } // Windows API [System.Runtime.InteropServices.DllImport("user32.dll")] private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam); private const uint WM_CLOSE = 0x0010; private void fun隐藏提示窗体() { if (下拉菜单 != null && 下拉菜单.Visible) { 下拉菜单.Close(); } } private void fun处理列表框按键(object sender, KeyEventArgs e事件参数) { switch (e事件参数.KeyCode) { case Keys.Enter: case Keys.Space: fun确认选择当前项(); e事件参数.Handled = true; e事件参数.SuppressKeyPress = true; break; case Keys.Escape: fun隐藏提示窗体(); e事件参数.Handled = true; e事件参数.SuppressKeyPress = true; break; case Keys.Tab: fun循环选择下一项(); e事件参数.Handled = true; e事件参数.SuppressKeyPress = true; break; } } private void fun处理列表框预览按键(object sender, PreviewKeyDownEventArgs e事件参数) { if (e事件参数.KeyCode == Keys.Tab) { e事件参数.IsInputKey = true; } } private void fun处理列表框双击(object sender, EventArgs e) { fun确认选择当前项(); } private void fun确认选择当前项() { if (lb候选词列表框.SelectedItem != null) { string str选中的词语 = lb候选词列表框.SelectedItem.ToString(); fun处理选中的词语(str选中的词语); } } private void fun循环选择下一项() { if (lb候选词列表框.Items.Count == 0) return; int n下一项索引 = (lb候选词列表框.SelectedIndex + 1) % lb候选词列表框.Items.Count; lb候选词列表框.SelectedIndex = n下一项索引; } private void fun处理选中的词语(string str选中的词语) { try { if (appWord应用.Selection != null) { Word.Selection sel当前选择 = appWord应用.Selection; int 原始光标位置 = sel当前选择.Start; System.Diagnostics.Debug.WriteLine($"处理选中词语: '{str选中的词语}', 缓存: '{str当前输入缓存}', 光标位置: {原始光标位置}"); // 删除已输入的文本 if (!string.IsNullOrEmpty(str当前输入缓存)) { int 词开始位置 = 原始光标位置 - str当前输入缓存.Length; if (词开始位置 >= 0 && 词开始位置 < 原始光标位置) { Word.Range 删除范围 = sel当前选择.Document.Range(词开始位置, 原始光标位置); string 删除前文本 = 删除范围.Text; System.Diagnostics.Debug.WriteLine($"删除范围: {词开始位置}-{原始光标位置}, 文本: '{删除前文本}'"); 删除范围.Text = ""; } } // 插入选中的词语 sel当前选择.Text = str选中的词语; // 移动光标到末尾 sel当前选择.Collapse(Word.WdCollapseDirection.wdCollapseEnd); // 清空缓存并隐藏 str当前输入缓存 = ""; fun隐藏提示窗体(); System.Diagnostics.Debug.WriteLine("插入完成,清空缓存"); } } catch (Exception ex异常) { System.Diagnostics.Debug.WriteLine($"插入选中词语时出错: {ex异常.Message}"); } } // 以下公共方法保持不变 public void fun设置功能启用状态(bool bl启用状态) { bl是否启用功能 = bl启用状态; if (!bl启用状态) { fun隐藏提示窗体(); } } public bool fun获取功能启用状态() { return bl是否启用功能; } public void fun设置候选词列表(List<string> lst新的候选词列表) { lst候选词列表 = lst新的候选词列表 ?? new List<string>(); } public void fun添加候选词(string str新词语) { if (!lst候选词列表.Contains(str新词语)) { lst候选词列表.Add(str新词语); } } public void fun刷新候选词列表(Func<List<string>> func获取候选词函数) { if (func获取候选词函数 != null) { lst候选词列表 = func获取候选词函数() ?? new List<string>(); } } public void fun合并候选词列表(List<string> lst额外候选词列表) { if (lst额外候选词列表 != null) { foreach (var str词语 in lst额外候选词列表) { if (!lst候选词列表.Contains(str词语)) { lst候选词列表.Add(str词语); } } } } public List<string> fun获取所有候选词() { return new List<string>(lst候选词列表); } public int fun获取候选词数量() { return lst候选词列表.Count; } public void fun清空输入缓存() { str当前输入缓存 = ""; fun隐藏提示窗体(); } } ====上述代码中,第一次输入“第”后会显示候选列表,再输入“二”时,第一次显示的候选列表不会消失,第二次触发要显示的列表就会在第一次显示的列表的后面,原因是什么?怎么才能在第二次显示候选列表前让第一次显示的候选列表消息?
09-30
#include <REGX52.H> #include <define.h> #include <LCD1602.h> #include <Buzzer.h> #include <MatrixKey.h> sbit Buzzer=P2^5; sbit LCD_RS=P2^6; sbit LCD_RW=P2^5; sbit LCD_EN=P2^7; #define LCD_DataPort P0 bit countdown = 0; // 倒计时状态:0=未开始,1=正在倒计时 uchar cd_shi = 0, cd_fen = 0, cd_miao = 0; // 倒计时剩余时长(时/分/秒 uchar count=0; //调时标志:1为秒,2为分,3为时 void delay(uint z) //延时函数 { uint x,y; for(x=z;x>0;x--) for(y=110;y>0;y--); } void write_com(uchar com) //写液晶命令函数 { LCD_RS=0; LCD_EN=0; P0=com; delay(5); LCD_EN=1; delay(5); LCD_EN=0; } void write_date(uchar date) //写液晶数据函数 { LCD_RS=1; LCD_EN=0; P0=date; delay(5); LCD_EN=1; delay(5); LCD_EN=0; } void init() //初始化函数 { // uchar num; // 中断初始化 EA=1; // 使能总中断 EX1=1; // 使能外部中断1 IT1=1; // 外部中断1设置为下降沿触发 TMOD |= 0x01; // 定时器0工作模式1(16位) //定时器0初始化(倒计时1秒计时) TH0 = (65536 - 10000) / 256; // 初值:10ms中断一次(12MHz晶振) TL0 = (65536 - 10000) % 256; ET0 = 1; // 使能定时器0中断 TR0 = 1; // 启动定时器0 flag1=0; // 闹钟设置标志位清零 t0_num=0; // 定时器0计数变量清零 week=1; // 星期初始化为1(周一) LCD_EN=0; rd=0; write_ds(0x0A,0x20); //打开震荡器 write_ds(0x0B,0X26); //设置24小时模式,数据二进制格式,开启闹铃中断 } void write_sfm(uchar add,uchar date) //液晶刷新时分秒函数:4为时,7为分,10为秒 { char shi,ge; shi=date/10; // 计算十位数字 ge=date%10; // 计算个位数字 write_com(0x80+0x40+add); // 设置显示位置(第二行) write_date(0x30+shi); // 显示十位(0x30是字符'0'的ASCII码) write_date(0x30+ge); // 显示个位 } void write_ds(uchar add,uchar date) //写DS12C887函数 { dscs=0; // 片选使能 dsas=1; // 地址锁存准备 dsds=1; // 数据锁存准备 dsrw=1; // 读写控制准备 P0=add; // 写入地址 dsas=0; // 锁存地址 dsrw=0; // 写使能 P0=date; // 写入数据 dsrw=1; // 结束写操作 dsas=1; // 释放地址锁存 dscs=1; // 释放片选 } uchar read_ds(uchar add) //读DS12C887函数 { uchar ds_date; dsas=1; // 地址锁存准备 dsds=1; // 数据锁存准备 dsrw=1; // 读写控制准备 dscs=0; // 片选使能 P0=add; // 写入要读取的地址 dsas=0; // 锁存地址 dsds=0; // 读数据使能 P0=0Xff; // 端口置高阻,准备读取 ds_date=P0; // 读取数据 dsds=1; // 结束读操作 dsas=1; // 释放地址锁存 dscs=1; // 释放片选 return ds_date; // 返回读取的数据 } void set_time() //首次上电初始化时间函数 { write_ds(0,0); // 秒初始化为0 write_ds(1,0); // 闹钟秒初始化为0 write_ds(2,0); // 分初始化为0 write_ds(3,0); // 闹钟分初始化为0 write_ds(4,0); // 时初始化为0 write_ds(5,0); // 闹钟时初始化为0 write_ds(6,0); // 星期初始化为0 write_ds(7,0); // 日初始化为0 write_ds(8,0); // 月初始化为0 write_ds(9,0); // 年初始化为0 } void keyscan() { uchar KeyNum; KeyNum=MatrixKey(); if(KeyNum==1) { Buzzer_Time(100); //计算标志:1为秒,2为分,3为时,4为退出调时模式 count++; } switch(count) { case 1: // 第1次按S1:设置"秒" write_com(0x80+0x40+7); // 光标定位到第2行第10列(秒的位置) write_com(0x0f); // 打开光标闪烁(提示当前正在设置该位置) break; case 2: // 第2次按S1:设置"分" write_com(0x80+0x40+4); // 光标定位到第2行第7列(分的位置) break; case 3: // 第3次按S1:设置"时" write_com(0x80+0x40+1); // 光标定位到第2行第4列(时的位置) break; case 4: count=0; //关闭调时模式 ; write_com(0x0c); // 关闭光标闪烁(退出设置状态) write_ds(0,miao); // 保存秒 // 将当前设置的时间写入DS12C887芯片(保存到硬件时钟) write_ds(2,fen); // 保存分 write_ds(4,shi); // 保存时 break; } if(count) //当S1被按下(即进入调整时间模式) { if(KeyNum==2) { Buzzer_Time(100); switch(count) { case 1: // 调节"秒" miao++; // 秒加1 if(miao==60) // 秒满60归零 miao=0; write_sfm(10,miao); // 更新液晶上的秒显示 write_com(0x80+0x40+10); // 保持光标在秒的位置 break; case 2: // 调节"分" fen++; // 分加1 if(fen==60) // 分满60归零 fen=0; write_sfm(7,fen); // 更新液晶上的分显示 write_com(0x80+0x40+7); // 保持光标在分的位置 break; case 3: // 调节"时" shi++; // 时加1 if(shi==24) // 时满24归零 shi=0; write_sfm(4,shi); // 更新液晶上的时显示 write_com(0x80+0x40+4); // 保持光标在时的位置 break; } } if(KeyNum==3) { Buzzer_Time(100); switch(count) { case 1: // 调节"秒" miao--; // 秒减1 if(miao==-1) // 秒减到-1时跳为59 miao=59; write_sfm(10,miao); // 更新液晶上的秒显示 write_com(0x80+0x40+10); // 保持光标在秒的位置 break; case 2: // 调节"分" fen--; // 分减1 if(fen==-1) // 分减到-1时跳为59 fen=59; write_sfm(7,fen); // 更新液晶上的分显示 write_com(0x80+0x40+7); // 保持光标在分的位置 break; case 3: // 调节"时" shi--; // 时减1 if(shi==-1) // 时减到-1时跳为23 shi=23; write_sfm(4,shi); // 更新液晶上的时显示 write_com(0x80+0x40+4); // 保持光标在时的位置 break; } } } if(KeyNum==4) //换倒计时模式 { Buzzer_Time(100); // 按键反馈音 countdown=~countdown; if(countdown==1) { cd_shi = shi; // 将当前调时的shi/fen/miao设为倒计时目标时长 cd_fen = fen; cd_miao = miao; write_sfm(4, cd_shi); // 显示初始倒计时时长 write_sfm(7, cd_fen); write_sfm(10, cd_miao); } } } void Timer0_ISR() interrupt 1 { // 重装定时器初值(12MHz晶振,10ms中断一次) TH0 = (65536 - 10000) / 256; TL0 = (65536 - 10000) % 256; t0_num++; // 累计中断次数(每10ms+1) // 累计100次=1000ms=1秒,触发倒计时递减 if (t0_num >= 100) { t0_num = 0; // 重置计数 // 仅在倒计时模式下执行递减 if (countdown == 1) { // 秒递减:秒>0时直接减1 if (cd_miao > 0) { cd_miao--; } // 秒=0但分>0:分减1,秒重置为59 else if (cd_fen > 0) { cd_fen--; cd_miao = 59; } // 分=0但时>0:时减1,分和秒重置为59 else if (cd_shi > 0) { cd_shi--; cd_fen = 59; cd_miao = 59; } // 时=分=秒=0:倒计时结束 else { countdown = 0; // 关闭倒计时模式 Buzzer_Time(500); // 蜂鸣器长鸣1秒提醒 // 回正常时间:读取DS12C887的真实时间并显示 shi = read_ds(4); fen = read_ds(2); miao = read_ds(0); write_sfm(4, shi); // 更新LCD为正常时间 write_sfm(7, fen); write_sfm(10, miao); return; // 结束本次中断处理 } } write_sfm(4, cd_shi); // 显示剩余时(第2行第4列) write_sfm(7, cd_fen); // 显示剩余分(第2行第7列) write_sfm(10, cd_miao); // 显示剩余秒(第2行第10列) } } void main() { init(); LCD_Init(); //调用初始化函数 LCD_ShowString(1,1,"count"); LCD_ShowString(1,11,"down"); LCD_ShowChar(1,6,':'); LCD_ShowChar(1,15,':'); LCD_ShowChar(2,7,'-'); LCD_ShowChar(2,10,'-'); while(1) { keyscan(); //按键扫描 LCD_ShowNum(1,7,count,1); // 在第一行第7列显示count(1位数) LCD_ShowNum(1,16,countdown,1); // 在第一行第16列显示countdown(1位数) if(countdown==0) { shi=read_ds(4); fen=read_ds(2); miao=read_ds(0); write_sfm(10,miao); // 更新LCD显示 write_sfm(7,fen); write_sfm(4,shi); } else { write_sfm(10,cd_miao); // 更新LCD显示 write_sfm(7,cd_fen); write_sfm(4,cd_shi); } } } void exter()interrupt 2 // 外部中断1服务程序(DS12C887闹钟中断) { uchar temp; // 正确读取C寄存器(地址0x0C),清除中断标志(必须严格时序) dscs = 0; // 片选使能 dsas = 1; // 地址锁存准备 dsrw = 1; // 读写准备 dsds = 1; // 数据锁存准备 P0 = 0x0C; // 写入C寄存器地址 dsas = 0; // 锁存地址(至少100ns,延时确保稳定) delay(1); // 延时1ms(兼容不同晶振) dsds = 0; // 读数据使能 delay(1); // 等待数据稳定 temp = P0; // 读取数据(清除中断标志的关键步骤) dsds = 1; // 关闭数据读取 dsas = 1; // 释放地址锁存 dscs = 1; // 释放片选 } 按照你的方法修改后为什么第2行的内容不断增加,最后LCD不显示任何东西
10-09
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值