为什么会发生 属性 写入错误?

Why is happened property write error?

c++ : 运行 发生时间错误,错误消息如下:

RevStrings1->Height of reading included in error: The property is write-protected.
RevStrings1->Height の読み込中のエラー : プロパティは書き込み禁止です.

我正在使用 c++ builder 3。

此源码可以编译成功 设置库,包含路径等

但是运行出现了时间错误


我猜这个问题是关于属性读写的。

我怎样才能简单地解决这个问题?

变量RevStrings1由classTRevStrings创建。

//---------------------------------------------------------------------------
#ifndef RevStringsH
#define RevStringsH
//---------------------------------------------------------------------------
#include <SysUtils.hpp>
#include <Controls.hpp>
#include <Classes.hpp>
#include <Forms.hpp>
#include <Grids.hpp>
//---------------------------------------------------------------------------
class PACKAGE TRevStrings : public TStringGrid
{
private:
//  void __fastcall SetWidth(int W);
//  int __fastcall GetWidth(void);
//  int FColCount ;
  int FRowCount;
  int FFixedCols ;
  int FFixedRows ;
  int FDefaultColWidth ;
  int FDefaultRowHeight ;
  int FHeight;
//  int FWidth;
  int FScrollBars;
  int FMaxLength;
  bool ColColors[24];

protected:
public:
    __fastcall TRevStrings(TComponent* Owner);
  void __fastcall DrawCellText(TRect ARect,int ALeft,String S);
  virtual void __fastcall DrawCell(int ACol, int ARow,const Windows::TRect &ARect, TGridDrawState AState);
  void __fastcall SetColor_Col(int Col,int Row);
  void __fastcall SetColorFlag(int Col,bool flag);
  bool __fastcall GetColorFlag(int Col);
  void __fastcall SetEditText(int ACol, int ARow,const System::AnsiString Value);
  void __fastcall Clear(bool ALLorONE,int Position);
  void __fastcall DblClick(void);
__published:
//  __property int ColCount = {read = FColCount};//FColCount};
  __property int RowCount = {read=FRowCount};
  __property int FixedCols = {read=FFixedCols};
  __property int FixedRows = {read=FFixedRows};
  __property int DefaultColWidth = {read=FDefaultColWidth};
  __property int DefaultRowHeight = {read=FDefaultRowHeight};
  __property int Height = {read=FHeight};
//  __property int Width = {read=GetWidth,write=SetWidth};
  __property int ScrollBars = {read=FScrollBars};
  __property int MaxLength = {read=FMaxLength,write=FMaxLength};
/*
*/
};
//---------------------------------------------------------------------------
#endif

之前从未听说过TRevStrings

所以它要么是 BCB 3 停产的东西(我的 BDS2006 没有它)或者你有一些第 3 方的习惯软件包已安装,但头文件表明它基于 TStringGrid,因此如果下面的文本对其不起作用,那么您可以改用 TStringGrid

TStringGrid

大小属性可以正常访问:

StringGrid1->Height=256;
StringGrid1->Width=128;

如果你想要大小合适的 col/rows 那么不要忘记打开选项 属性 并将 goRowSizing,goColSizing 设置为 true 并且起始尺寸为 DefaultColWidth,DefaultRowHeight.这里的用法示例

// resize the grid
StringGrid1->Height=128;
StringGrid1->Width=256;
// access to Cell AnsiStings
StringGrid1->Cells[0][0]="(0,0)";
StringGrid1->Cells[1][1]="(1,1)";
StringGrid1->Cells[1][2]="(1,2)";
StringGrid1->Cells[2][1]="(2,1)";
// resizing row/col
StringGrid1->RowHeights[0]=15;
StringGrid1->RowHeights[1]=20;
StringGrid1->ColWidths[0]=20;
StringGrid1->ColWidths[1]=15;

因为你的 class 是从这里派生出来的所以这应该也适用于它,如果不是的话还有更多的可能性:

  1. 你在某处有不相关的错误

    覆盖你不应该损坏的 C++ 引擎你的应用 运行 或在某处有内存泄漏或你的内存管理器无效见

    • bds 2006 C hidden memory manager conflicts

    但情况可能并非如此,或者您正在从线程调用 VCL/Winapi 视觉内容。

要检查所有这些:

创建空应用程序,添加您的 TRevString 并尝试在运行时设置其高度。如果没有发生错误,那么如果发生错误,则说明某处存在错误:

  1. 此组件无法以这种方式在运行时调整大小

    尝试使用 SetSize,SetBounds 之类的功能,或者将组件放在某个面板上与客户端对齐并调整面板大小

  2. 如果即使这样也不能帮助切换到标准 TStringGrid

    你也可以尝试先把你RevString转换成StringGrid

    ((TStringGrid*)(RevString1))->Height=25;
    
  3. Borland 编译器有时会变得奇怪

    多年来我使用 BCB/BDS 几次(大约 10 次)编译器有时会编译错误。该应用程序是 运行,但一些代码被扭曲或丢弃,所以有什么帮助?

    • 关闭IDE甚至重启Windows
    • 在编译重建之前删除所有 map,obj,tds 个临时文件
    • 有时需要您添加空行代码或交换 2 行代码
  4. Identifiers/Names 碰撞

    如果您以类似于 VCL 函数的方式命名您的东西,那么您会遇到问题,通常的错误是将函数命名为 Draw() ...(使用 draw() 相反,你很好)

  5. 大项目

    如果您将源代码作为新单元添加到项目而不是仅仅包含它(它存在于对象管理器中),那么在大项目中您将遇到大问题。看起来单位的编译方式与单位中的正常包含文件不同 公式和其他 VCL 东西组件因此,如果您有自己的非可视化 classes 作为单位,它们有时会停止按预期工作会产生奇怪的行为(甚至你的错误也可能是由它引起的)。

    我在 BCB5BDS2006 上观察到了这一点。在 BCB3,BCB4 中,我没有制作足够大的项目来发现这一点,而且 BCB6 有很多错误,所以无论如何它都无法用于大型项目。我所说的大项目是指 > 1 MB 的纯 C++ 代码

错误是不言自明的 - RevStrings1 对象的 Height 属性 不允许分配其值。通过查看 TRevStrings class 中 Height 属性 的声明可以明显看出这一点:

__property int Height = {read=FHeight};

TRevStrings 正在竭尽全力使 Height 属性 只读,覆盖 本机读写 Height 属性 继承自 TControl:

__property int Height = {read=FHeight, write=SetHeight, nodefault};

TRevString 这样做很奇怪,因为它是一个可视化组件,需要进行缩放。除非它需要用户无法更改的特定高度(在这种情况下,将 Height 属性 声明为只读不是处理该问题的正确方法 - 组件应覆盖虚拟 SetBounds() 方法,并忽略任何新的 Height 分配的值)。

也就是说,您在 运行 时看到错误的原因是因为 IDE 正在存储 RevStrings1 的设计时 Height 值在编译时父窗体的 DFM 资源中的对象。这就是为什么您在代码中找不到任何 RevStrings1->Height - 它来自表单设计器。 TRevStrings class 不会覆盖 Height 属性 的 DFM 行为,因此当 VCL 的 DFM 流系统在 运行 时解析窗体的 DFM 资源时,它看到存储的 Height 值并检测到对象的 Height 属性 实际上是只读的,因此抛出异常以取消 DFM 流式处理(以及表单的构造)。

这是 TRevStrings 实现中的错误。至少,如果作者想要阻止 Height 被流式传输(从而防止 运行-time 错误),则应该声明 Height 属性像这样:

__property Height = {read=FHeight, stored=false};

附带说明,TRevStrings 数据成员中的 大多数 FColCountFRowCountFFixedColsFFixedRows, etc) 应该 never 根本没有被声明,而是应该从基础 TStringGrid class.

继承

写这个组件的人显然不知道他们在做什么。