Edit,Memo,Treeview加背景图片

本文介绍了一种改进的方法来实现在文本区域中显示图片的功能,通过调整代码以支持图片的加载和显示。

//本方法不够完善,比如滚动条还不能加载图片

 

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, StdCtrls;

type
  TForm1 = class(TForm)
    Memo1: TMemo;
    Image1: TImage;
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations } 
    procedure HandleCTLColorEdit(var Msg: TWMCTLCOLOREDIT);
      message WM_CTLCOLOREDIT;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  Memo1.Brush.Bitmap := Image1.Picture.Bitmap; // 这里背景图片取image1里的图片
  Memo1.Repaint;
end;

procedure TForm1.HandleCTLColorEdit(var Msg: TWMCTLCOLOREDIT);
begin
  inherited;

  if Msg.ChildWnd = Memo1.Handle then
  begin
    SetBkMode(Msg.ChildDC, TRANSPARENT);
    Msg.Result := Memo1.Brush.Handle;
  end;

end;

end.

 

 

// DFM

object Form1: TForm1
  Left = 215
  Top = 126
  Width = 390
  Height = 287
  Caption = 'Form1'
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  OldCreateOrder = False
  OnCreate = FormCreate
  DesignSize = (
    382
    260)
  PixelsPerInch = 96
  TextHeight = 13
  object Image1: TImage
    Left = 216
    Top = 64
    Width = 105
    Height = 105
    Picture.Data = {
      07544269746D6170AE000000424DAE0000000000000036000000280000000100
      00001E000000010018000000000078000000C40E0000C40E0000000000000000
      00004FA2C500F2FCFF00C2F4FF00C3F4FF00C5F5FF00C7F5FF00C9F6FF00CBF6
      FF00CCF6FF00CEF7FF00D0F7FF00D1F8FF00D3F8FF00D5F8FF00D6F9FF00D8F9
      FF00DAFAFF00DBFAFF00DDFAFF00DEFBFF00DFFBFF00E1FBFF00E2FCFF00E3FC
      FF00E4FCFF00E5FCFF00E6FDFF00E7FDFF00FAFFFF004FA2C500}
  end
  object Memo1: TMemo
    Left = 32
    Top = 24
    Width = 313
    Height = 193
    Anchors = [akLeft, akTop, akRight, akBottom]
    Font.Charset = DEFAULT_CHARSET
    Font.Color = clWindowText
    Font.Height = -24
    Font.Name = 'MS Sans Serif'
    Font.Style = []
    Lines.Strings = (
      'Memo1')
    ParentFont = False
    ScrollBars = ssBoth
    TabOrder = 0
    OnChange = Memo1Change
  end
end

请继续优化交易备忘录代码:# -*- coding: utf-8 -*- import tkinter as tk from tkinter import ttk, messagebox, filedialog import os import struct import traceback from collections import defaultdict class TdxDataParser: """通达信数据解析器(支持自定义路径)""" def __init__(self, tdx_path=None): self.tdx_path = tdx_path or self._find_default_path() self.stock_dict = {} self.validate_tdx_path() self.load_stock_info() def _find_default_path(self): """尝试自动查找通达信安装路径""" possible_paths = [ r"D:\new_tdx", r"C:\new_tdx", r"D:\TdxW", r"C:\TdxW" ] for path in possible_paths: if os.path.exists(path): return path return None def validate_tdx_path(self): """验证通达信路径及必要文件""" if not self.tdx_path: raise FileNotFoundError("未找到通达信安装目录,请手动选择") required_files = [ "T0002/hq_cache/shm.tnf", "T0002/hq_cache/szm.tnf", "vipdoc/sh/lday", "vipdoc/sz/lday" ] for rel_path in required_files: full_path = os.path.join(self.tdx_path, rel_path.replace("/", os.sep)) if not os.path.exists(full_path): raise FileNotFoundError(f"缺失必要文件或目录:{full_path}") if not os.access(full_path, os.R_OK): raise PermissionError(f"无权限访问路径:{full_path}") def load_stock_info(self): """载股票代码表(带缓存)""" self.stock_dict = {} try: # 使用缓存载 cache_path = os.path.join(self.tdx_path, ".stock_cache") if os.path.exists(cache_path): with open(cache_path, "r", encoding="utf-8") as f: for line in f: code, name = line.strip().split("|") self.stock_dict[code] = name return # 解析沪市代码表 self._parse_tnf_file( os.path.join(self.tdx_path, "T0002", "hq_cache", "shm.tnf"), market="SH" ) # 解析深市代码表 self._parse_tnf_file( os.path.join(self.tdx_path, "T0002", "hq_cache", "szm.tnf"), market="SZ" ) # 创建缓存 with open(cache_path, "w", encoding="utf-8") as f: for code, name in self.stock_dict.items(): f.write(f"{code}|{name}\n") except Exception as e: raise RuntimeError(f"股票代码载失败: {str(e)}") def _parse_tnf_file(self, file_path, market): """解析shm/szm文件(带进度条)""" try: with open(file_path, "rb") as f: while True: block = f.read(288) # 每个记录块288字节 if not block or len(block) < 288: break # 解析股票代码(6字节ASCII) code = block[0:6].decode("ascii").strip() # 解析股票名称(16-32字节GBK编码) name = block[16:32].decode("gbk").strip() if code and name: self.stock_dict[f"{market}{code}"] = name except FileNotFoundError: raise RuntimeError(f"未找到代码表文件: {file_path}") def get_day_data(self, code): """读取日线数据(支持分页载)""" market = "sh" if code.startswith("SH") else "sz" file_path = os.path.join( self.tdx_path, "vipdoc", market, "lday", f"{code.lower()}.day" ) try: data_list = [] with open(file_path, "rb") as f: while True: record = f.read(32) # 每次读取32字节 if not record: break # 使用提供的解析方法 unpacked = struct.unpack("<iffffiix", record) data = { "date": str(unpacked[0]), "open": round(unpacked[1], 2), "high": round(unpacked[2], 2), "low": round(unpacked[3], 2), "close": round(unpacked[4], 2), "volume": unpacked[5], "amount": unpacked[6] } data_list.append(data) return data_list except FileNotFoundError: raise RuntimeError(f"未找到日线数据文件: {file_path}") except Exception as e: raise RuntimeError(f"日线数据读取失败: {str(e)}") class TradeMemoApp: """交易备忘录主程序(优化版)""" def __init__(self): self.root = tk.Tk() self.root.title("交易备忘录 - 通达信数据查看器 v2.0") self.root.geometry("1200x800") self.root.protocol("WM_DELETE_WINDOW", self.on_close) # 初始化解析器 self.tdx_parser = None self.current_code = "" self.data_cache = defaultdict(list) # 数据缓存 # 创建界面 self.create_widgets() self.load_settings() # 自动载数据 if self.tdx_parser: self.update_status("就绪 - 已载通达信数据") else: self.select_tdx_path() def create_widgets(self): """创建界面组件""" # 样式设置 style = ttk.Style() style.configure("Header.TLabel", font=("微软雅黑", 10, "bold")) # 菜单栏 menubar = tk.Menu(self.root) file_menu = tk.Menu(menubar, tearoff=0) file_menu.add_command(label="选择通达信路径", command=self.select_tdx_path) file_menu.add_command(label="导出数据", command=self.export_data) file_menu.add_separator() file_menu.add_command(label="退出", command=self.on_close) menubar.add_cascade(label="文件", menu=file_menu) help_menu = tk.Menu(menubar, tearoff=0) help_menu.add_command(label="关于", command=self.show_about) menubar.add_cascade(label="帮助", menu=help_menu) self.root.config(menu=menubar) # 顶部区域 top_frame = ttk.Frame(self.root) top_frame.pack(padx=10, pady=5, fill=tk.X) # 路径显示 path_frame = ttk.LabelFrame(top_frame, text="通达信路径") path_frame.pack(side=tk.LEFT, expand=True, fill=tk.X) self.path_var = tk.StringVar() self.path_entry = ttk.Entry( path_frame, textvariable=self.path_var, state="readonly" ) self.path_entry.pack(side=tk.LEFT, expand=True, fill=tk.X) # 路径选择按钮 ttk.Button( top_frame, text="...", width=3, command=self.select_tdx_path ).pack(side=tk.LEFT, padx=5) # 股票代码输入 code_frame = ttk.Frame(self.root) code_frame.pack(padx=10, pady=5, fill=tk.X) ttk.Label(code_frame, text="股票代码:", width=10).pack(side=tk.LEFT) self.code_var = tk.StringVar() self.code_entry = ttk.Entry(code_frame, textvariable=self.code_var, width=15) self.code_entry.pack(side=tk.LEFT, padx=5) self.code_entry.bind("<KeyRelease>", self.on_code_change) self.name_label = ttk.Label(code_frame, text="股票名称", width=30) self.name_label.pack(side=tk.LEFT) # 数据表格 tree_frame = ttk.Frame(self.root) tree_frame.pack(padx=10, pady=5, expand=True, fill=tk.BOTH) # 创建带滚动条的表格 self.tree = ttk.Treeview(tree_frame, show="headings") self.tree["columns"] = ( "日期", "开盘价", "最高价", "最低价", "收盘价", "成交量", "成交额" ) # 配置各列 col_widths = { "日期": 100, "开盘价": 80, "最高价": 80, "最低价": 80, "收盘价": 80, "成交量": 100, "成交额": 120 } for col in self.tree["columns"]: self.tree.column(col, width=col_widths[col], anchor="center") self.tree.heading(col, text=col) # 滚动条 vsb = ttk.Scrollbar(tree_frame, orient="vertical", command=self.tree.yview) hsb = ttk.Scrollbar(tree_frame, orient="horizontal", command=self.tree.xview) self.tree.configure(yscrollcommand=vsb.set, xscrollcommand=hsb.set) # 布局 self.tree.pack(side="left", fill="both", expand=True) vsb.pack(side="right", fill="y") hsb.pack(side="bottom", fill="x") # 状态栏 self.status_bar = ttk.Label(self.root, text="就绪", relief=tk.SUNKEN) self.status_bar.pack(side=tk.BOTTOM, fill=tk.X) def load_settings(self): """载保存的设置""" config_path = os.path.join(os.path.expanduser("~"), ".trade_memo_config") if os.path.exists(config_path): with open(config_path, "r") as f: for line in f: key, value = line.strip().split("=") if key == "tdx_path" and os.path.exists(value): self.tdx_path = value self.path_var.set(value) try: self.tdx_parser = TdxDataParser(value) except Exception as e: messagebox.showerror("错误", f"载配置路径失败: {str(e)}") def save_settings(self): """保存设置""" config_path = os.path.join(os.path.expanduser("~"), ".trade_memo_config") with open(config_path, "w") as f: f.write(f"tdx_path={self.tdx_path}\n") def select_tdx_path(self): """选择通达信安装路径""" path = filedialog.askdirectory(title="选择通达信安装目录") if path: try: self.tdx_parser = TdxDataParser(path) self.tdx_path = path self.path_var.set(path) self.save_settings() self.update_status(f"已切换路径: {path}") except Exception as e: messagebox.showerror("错误", f"选择路径失败: {str(e)}") def on_code_change(self, event=None): """股票代码变化处理""" if not self.tdx_parser: return code = self.code_var.get().upper() # 自动补全市场代码 if len(code) == 6: if code.startswith("6"): code = "SH" + code elif code.startswith(("0", "3")): code = "SZ" + code self.code_var.set(code) # 验证代码有效性 if len(code) < 8 or not code.startswith(("SH", "SZ")): return # 显示股票信息 name = self.tdx_parser.stock_dict.get(code, "未知代码") self.name_label.config(text=name) # 载日线数据(使用缓存) if code in self.tdx_parser.stock_dict: if code in self.data_cache: self.current_code = code self.display_data(self.data_cache[code]) self.update_status(f"显示{code}缓存数据") else: self.current_code = code self.load_day_data(code) def load_day_data(self, code): """载并缓存日线数据""" try: data = self.tdx_parser.get_day_data(code) if data: self.data_cache[code] = data self.display_data(data[-30:]) # 显示最近30条 self.update_status(f"显示{code}最近{len(data[-30:])}条日线数据") except Exception as e: messagebox.showerror("错误", str(e)) def display_data(self, data): """显示数据到表格""" # 清空现有数据 self.tree.delete(*self.tree.get_children()) # 显示数据 for item in data: self.tree.insert("", 0, values=( item["date"], item["open"], item["high"], item["low"], item["close"], f"{item['volume']:,}", f"{item['amount']:,}" )) def update_status(self, message): """更新状态栏""" self.status_bar.config(text=message) def export_data(self): """导出数据为CSV""" if not self.current_code or not self.data_cache.get(self.current_code): messagebox.showwarning("警告", "请先载数据") return file_path = filedialog.asksaveasfilename( defaultextension=".csv", filetypes=[("CSV文件", "*.csv"), ("所有文件", "*.*")] ) if file_path: try: with open(file_path, "w", encoding="utf-8-sig", newline="") as f: f.write("日期,开盘价,最高价,最低价,收盘价,成交量,成交额\n") for item in self.data_cache[self.current_code]: f.write(f"{item['date']},{item['open']},{item['high']},{item['low']},{item['close']},{item['volume']},{item['amount']}\n") messagebox.showinfo("成功", "数据导出成功") except Exception as e: messagebox.showerror("错误", f"导出失败: {str(e)}") def show_about(self): """显示关于信息""" messagebox.showinfo("关于", "交易备忘录 v2.0\n作者: AI助手\n基于通达信数据解析") def on_close(self): """关闭事件处理""" if messagebox.askokcancel("退出", "确定要退出程序吗?"): self.root.destroy() if __name__ == "__main__": try: app = TradeMemoApp() app.root.mainloop() except Exception as e: messagebox.showerror("致命错误", f"程序启动失败: {str(e)}\n详情请查看日志。") print("致命错误:", str(e)) print(traceback.format_exc())
最新发布
12-18
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值