tagCANDY CGI VBレスキュー(花ちゃん) の Visual Basic 2010 用 掲示板(VB.NET 掲示板) [ツリー表示へ]   [Home]
一括表示(VB.NET VB2005)
タイトルLabelのダブルクリックでテキストのコピーが邪魔
記事No12311
投稿日: 2025/05/26(Mon) 21:33
投稿者たこやき
お世話になります。
本サイト初投稿です。

VB2005環境です。

[ツリー表示へ]
タイトルLabelのダブルクリックでテキストのコピーが邪魔
記事No12312
投稿日: 2025/05/26(Mon) 23:24
投稿者たこやき
マイクロソフトの中の○×△□がバージョンアップするときに余計なことをしたらしいです。
Labelをダブルクリックをすると、Label.Textがクリップボードに自動コピーされるように変わったそうです。

新しいバージョンではe.Cancel=Trueで自動コピーを停止できますが、
古いバージョンではe.Cancelのメンバー自体がありません。

なのに、自動コピーをデフォルトにしたようです。
つまり自動コピーを普通に止めることができません。
愚かで愚かで迷惑千万な話です。

仕方が無いのでコーディングしてみました。
透明のPictureBoxをLabelの上に載せて、Labelを直接クリックできなくしましたが、
…泥臭くて格好悪いです。

    Private Shared Function CoverLabelWithPictureBox( _
        ByVal Label As System.Windows.Forms.Label _
    ) As Integer
'省略割愛
            Return CoverLabelWithPictureBox(Label, New System.Windows.Forms.PictureBox)
'省略割愛
    End Function

    Private Shared Function CoverLabelWithPictureBox( _
        ByVal Label As System.Windows.Forms.Label, _
        ByVal PictureBox As System.Windows.Forms.PictureBox _
    ) As Integer
'省略割愛
        Dim lbl As System.Windows.Forms.Label
        Dim pct As System.Windows.Forms.PictureBox
'省略割愛
            lbl = Label
            pct = PictureBox

            If pct.BackColor <> Color.Transparent Then pct.BackColor = Color.Transparent
            If pct.Left <> 0 Then pct.Left = 0
            If pct.Top <> 0 Then pct.Top = 0
            If pct.Width <> lbl.Width Then pct.Width = lbl.Width
            If pct.Height <> lbl.Height Then pct.Height = lbl.Height
            If Not pct.Parent Is lbl Then pct.Parent = lbl
'省略割愛
'おまけ、'Private WithEvents PictureBox1 As New System.Windows.Forms.PictureBox
    End Function


この泥臭いコードより、良い感じのコードがあるなら、教えてください。

[ツリー表示へ]
タイトルRe: Labelのダブルクリックでテキストのコピーが邪魔
記事No12313
投稿日: 2025/05/27(Tue) 11:46
投稿者魔界の仮面弁士
> マイクロソフトの中の○×△□がバージョンアップするときに余計なことをしたらしいです。
> Labelをダブルクリックをすると、Label.Textがクリップボードに自動コピーされるように変わったそうです。
少なくとも 15 年以上前からそういう動作になっていますね。
「XP Visualスタイルを有効にする」をオフにした場合は無効化されます。
Vista 以降に限定されていて、Windows XP だとコピーされないんじゃなかったかな…?

これは OS 側の仕様なので、非 .NET アプリでもコモンダイアログ上のラベルでは同様の動作になります。
C++ のスタティックコントロールでは、ダブルクリックでコピーされないのですけれどね。


> 新しいバージョンではe.Cancel=Trueで自動コピーを停止できますが、
> 古いバージョンではe.Cancelのメンバー自体がありません。
少なくとも .NET 8.0 や .NET Framework 4.8.1 においては、
Label の DoubleClick / MouseDoubleClick イベントに e.Cancel を確認できませんでした。
具体的には、どのバージョンのどのイベント(またはオーバーライダブルメソッド)のことを指していますか?


> 仕方が無いのでコーディングしてみました。
メッセージを追跡してみると、
 WM_LBUTTONDBLCLK
 WM_GETTEXTLENGTH
 WM_GETTEXT
 WM_LBUTTONUP
が飛んできているので、ダブルクリック後のテキスト操作を握りつぶしてしまってはどうでしょうか?
たとえば、Label クラスを Inherits した自作クラスを用意してこんな感じ。


Public Class LabelEx
    Inherits Label

    Private doubleClicking As Boolean = False
    Protected Overrides Sub WndProc(ByRef m As Message)
        Const WM_LBUTTONDBLCLK As Integer = &H203
        If m.Msg = WM_LBUTTONDBLCLK Then
            doubleClicking = True
        End If
        MyBase.WndProc(m)
    End Sub

    Protected Overrides Sub DefWndProc(ByRef m As Message)
        Const WM_GETTEXTLENGTH As Integer = &HE
        If m.Msg = WM_GETTEXTLENGTH AndAlso doubleClicking Then
            doubleClicking = False
        Else
            MyBase.DefWndProc(m)
        End If
    End Sub
End Class

あとは、Form1.designer.vb 内の InitializeComponent で
 Me.Label1 = New System.Windows.Forms.Label()

 Me.Label1 = New LabelEx()
に置き換えて使います。文字数 0 を返すことでクリップボード転送されずに
済むようですが、これは実際の動作からの経験則に過ぎず、正規の方法では無いため
他の環境でも使える方法なのかどうかは保証できません。


まぁ、OpenFileDialog で表示されるダイアログの「ファイル名:」ラベルなどは
先述の通り、やはりダブルクリックでコピーされてしまうのですけれどね。

[ツリー表示へ]
タイトルRe^2: Labelのダブルクリックでテキストのコピーが邪魔
記事No12314
投稿日: 2025/05/27(Tue) 18:52
投稿者魔界の仮面弁士
> C++ のスタティックコントロールでは、ダブルクリックでコピーされないのですけれどね。

間違い。Static コントロールであっても、SS_NOTIFY スタイル付きだとコピーされるそうです。
https://devblogs.microsoft.com/oldnewthing/20120301-00/?p=8193

ということは、既存の Label すべてを継承で置き換えずとも、
SS_NOTIFY スタイルを付け外しするような処理を用意することで、
Label コピー機能の on/off をフォーム単位で制御できるかも知れません。

1) コンストラクタ引数で Form を受け取るクラスを用意する
2) その処理で、Form の Controls を子孫まで列挙し、すべてのコントロールを列挙する
3) 動的な追加のために、ControlAdded イベントにも同様の列挙処理を仕込む
4) 2 や 3 で、すべての Label のウィンドウハンドルを得て、SS_NOTIFY スタイルを
 GetWindowLong / SetWindowLong で付け外しする。

※現時点では、上記は私の思考実験です。実際に動作するかは検証していません。

[ツリー表示へ]
タイトルRe^2: Labelのダブルクリックでテキストのコピーが邪魔
記事No12315
投稿日: 2025/05/29(Thu) 02:40
投稿者たこやき
返信ありがとうございました。



> 少なくとも 15 年以上前からそういう動作になっていますね。

15年以上前に現場から離れたとはいえ、うっかりさんなのか、ずっと気付いてなかったです。



> 具体的には、どのバージョンのどのイベント(またはオーバーライダブルメソッド)のことを指していますか?

古過ぎてごめんなさいVB2005は2.0です。
現場を離れてから、新しい環境に触れなかったので…。
でも、環境整備にネット接続が一切いらないので未だに手放せない良い子です。
マイクロソフト側の認証サーバーが消滅しても使えるのは良いことです。
当時高いOfficeEditionを買えば良かったと未だに後悔してます。



> たとえば、Label クラスを Inherits した自作クラスを用意してこんな感じ。

サンプルコードの提供ありがとうございます。
やはり、継承したクラス作るのが王道ですよね…。

アップデートするときGUIのツールボックスでコントロールを再配置したいので、
Designer.vbには直接コードに触りたくないのと、
MouseDoubleClickイベントを使ってるので、
イベント自体潰しちゃうと使えなくなってしまいますね…
(別途イベントを発行するだけでいいんですけどね)。

…わがままばかり…。


わがままを実現させるには、
LabelのオブジェクトをClass.Newに引き渡して、
Class内部でLabel(引数)とPictureBoxのWithEventsで定義して、
内部のLabelとPictureBoxのイベントを全部拾ってClassのイベントとして扱い、
そのClassをWithEventsで呼び出してイベントとして扱う。
LabelとPictureBoxのプロパティも全部アクセスできるように整える。
Labelのサイズ変更にもPicutureBoxを追従させる。
超泥臭くて嫌だなぁ。

それとも、フォームロード時に継承クラスを作ってメンバーをコピーして差し替える方が楽かな。
うーん、迷う。



> まぁ、OpenFileDialog で表示されるダイアログの「ファイル名:」ラベルなどは
> 先述の通り、やはりダブルクリックでコピーされてしまうのですけれどね。

もう、これ考えた○×△□はアホですね。

[ツリー表示へ]
タイトルRe^3: Labelのダブルクリックでテキストのコピーが邪魔
記事No12316
投稿日: 2025/05/29(Thu) 11:56
投稿者魔界の仮面弁士
> > 具体的には、どのバージョンのどのイベント(またはオーバーライダブルメソッド)のことを指していますか?
> 古過ぎてごめんなさいVB2005は2.0です。

もう一度質問を繰り返します。

たこやきさんが使っているのが、VB2005 + .NET Framework 2.0 というのは分かりましたが、
『新しいバージョンではe.Cancel=Trueで自動コピーを停止できますが』という先の発言は、
どのバージョンの .NET における、どのイベント引数のことを指しているのでしょうか?


> やはり、継承したクラス作るのが王道ですよね…。
コントロールを差し替えたくないのなら、NativeWindow クラスでサブクラス化して
WM_LBUTTONDBLCLK 時の処理を握りつぶしてしまえば良いかと思います。


> MouseDoubleClickイベントを使ってるので、
> イベント自体潰しちゃうと使えなくなってしまいますね…
ダブルクリック イベント自体は必要、という話になると、
No.12314 のように、SS_NOTIFY スタイルを解除する案も駄目かも知れませんね。
No.12313 のように、WM_GETTEXTLENGTH でゼロを返すようにサブクラス化したらどうなりますか?
(Win10 でしか試してないので、Win11 でうまくいくかは分かりません)

[ツリー表示へ]
タイトルRe^4: Labelのダブルクリックでテキストのコピーが邪魔
記事No12317
投稿日: 2025/05/29(Thu) 23:32
投稿者たこやき
> 『新しいバージョンではe.Cancel=Trueで自動コピーを停止できますが』という先の発言は、
> どのバージョンの .NET における、どのイベント引数のことを指しているのでしょうか?

既に忘れてます。
マイクロソフトのサイトで見たと思いますけど、再度調べる気にはならないです。
「どうしよう→検索→マイクロソフトの何か→なるほど、これで解決だな(あったか?)→ないじゃん!?」
なので、自分で試して確認してないです。

なお、
  Private Sub Label1_MouseDoubleClick(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Label1.MouseDoubleClick
の「e」です。
e.Handlerもe.Cancelもないですね。

'上記から呼び出す予定だった使い物にならないゴミ関数
    Private Shared Function CancelCopyAtLabelDoubleClick(ByVal e As System.Windows.Forms.MouseEventArgs) As Integer
'略
            If e.Clicks >= 2 Then
                e.Cancel = True 'そんなプロパティありません
            End If
'略
    End Function

なんか落ちてないかなと思って継承しても、
    Public Class NewMouseEventArgs
        Inherits System.Windows.Forms.MouseEventArgs
        Public Sub New(ByVal button As System.Windows.Forms.MouseButtons, ByVal clicks As Integer, ByVal x As Integer, ByVal y As Integer, ByVal delta As Integer)
            MyBase.New(button, clicks, x, y, delta)
        End Sub
    End Class
引数を見る限り詰んでました。



> > やはり、継承したクラス作るのが王道ですよね…。
> コントロールを差し替えたくないのなら、NativeWindow クラスでサブクラス化して
> WM_LBUTTONDBLCLK 時の処理を握りつぶしてしまえば良いかと思います。
>
> > MouseDoubleClickイベントを使ってるので、
> > イベント自体潰しちゃうと使えなくなってしまいますね…
> ダブルクリック イベント自体は必要、という話になると、
> No.12314 のように、SS_NOTIFY スタイルを解除する案も駄目かも知れませんね。
> No.12313 のように、WM_GETTEXTLENGTH でゼロを返すようにサブクラス化したらどうなりますか?
> (Win10 でしか試してないので、Win11 でうまくいくかは分かりません)

前提として、
コードを直接書いて良いエリアと書いてはいけないエリアで分けてます。
Designer.vbのコードを直接触らないと書いたとおり、
VSのフォーム表示なGUI操作(Form1 [デザイン])のときの影響が嫌なので
Designer.vbに影響を及ぼすコントロール系では継承や処理を手前で変えるのを避けてます。
コントロールを継承したものを使うのはForm_Load以降です。



今回どう対応するかを自分の考えを確認したところ、

・Designer.vbはフォーム表示環境のGUI操作経由以外では触らない
・何かやるならForm_Load時にやる
・Label風コントロールのイベントを普通に使えるようにする
・他のコントロールのイベントの影響があっても支障ない
・他のプロジェクトで再利用するとき、書き込むコードの増量を(ラベル1つあたり)3行以内にする☆ここ大事☆
 例(2行):
 @Private WithEvents NewLabelClass1 As NewLabelClass
  : :
 ANewLabelClass1 = New NewLabelClass(Label1) 'Form_Load時
というのを満たすことを前提にしてますね。


たぶん上記例の延長線上には、
NewLabelClassはPictureBoxを継承し、内部では

Public Property Text As String 'ラベルに引き渡す

'ラベルのイベントを捕まえて、代わりにイベントを出す
Public Shadows Event TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs)

というのを作ったり、

Dock(PictureBoxはFill固定、Dock自体はLabelに渡す)、
BackColor(PictureBoxは透明固定、色変更はLabelに渡す)、
その他Anchor,ForeColor,Fonts等々のPropetyを上書きします。

このときデッドロックが起きないよう
全プロパティにSystem.Threading.MutexとSyncLockを使わないといけない。

概ねこういう方向性で対応することになると思います。

[ツリー表示へ]