用java 操作word 使其变成图片和文字对齐 (最好是操作页脚)

img

用java 操作word 使其变成图片和文字对齐 (最好是操作页脚)图片和文字都需要新插入进去word的

img

word中对齐的方法:

img

但是java怎么这样操作就不会了

问题跟这个同志的一样,但是他的解答看不懂,希望哥们回答的时候直接上代码和效果截图,感谢!
https://ask.csdn.net/questions/7762178

这是我自己的代码:

public R addSignature() throws Exception {

        Document doc = new Document("D:/sample.docx");


        //获取第一节
        Section sec = doc.getSections().get(0);

        //删除页脚
        sec.getHeadersFooters().getFooter().getChildObjects().clear();

        HeaderFooter footer = sec.getHeadersFooters().getFooter();
        Paragraph fpara= footer.addParagraph();
        fpara.appendText("试验:");
        fpara.getFormat().setHorizontalAlignment(HorizontalAlignment.Center);

        DocPicture pic =fpara.appendPicture("D:/图片1.png");
        pic.setVerticalAlignment(ShapeVerticalAlignment.Center);
        pic.setHorizontalAlignment(ShapeHorizontalAlignment.Center);
        doc.saveToFile("D:/sample.docx", FileFormat.Docx_2013);

        return R.ok();
    }

这是运行的结果

img

你图上的文本对齐方式是专门针对中文版式的设置,感觉目前很少有类库支持这个。但是你可以用另一个替代方法,就是表格来实现类似效果。
下面是实现代码和结果,如果有帮到你,希望能采纳:

import com.spire.doc.*;
import com.spire.doc.documents.*;
import com.spire.doc.fields.TextRange;

public class AddFooter {
    public static void main(String[] args) {
        //加载Word文档
        Document doc= new Document("test.docx");
        //获取文档第一个节
        Section sec = doc.getSections().get(0);

        //获取该节的页脚
        HeaderFooter footer = sec.getHeadersFooters().getFooter();

        //创建一个1行2列的表格
        Table table = footer.addTable();
        table.resetCells(1,2);

        //获取第一行
        TableRow row = table.getRows().get(0);

        //添加段落到第一个单元格
        Paragraph paragraph = row.getCells().get(0).addParagraph();
        //添加文本到段落并设置字体
        TextRange text = paragraph.appendText("试验");
        text.getCharacterFormat().setFontName("宋体");
        //设置文本水平对齐方式为右对齐
        paragraph.getFormat().setHorizontalAlignment(HorizontalAlignment.Right);
        //设置文本垂直对齐方式为居中对齐
        row.getCells().get(0).getCellFormat().setVerticalAlignment(VerticalAlignment.Middle);

        //添加图片到第二个单元格
        row.getCells().get(1).addParagraph().appendPicture("logo.png");

        //移除表格边框
        table.getTableFormat().getBorders().setBorderType(BorderStyle.None);

        //设置表格对齐方式为居中(即文字和图片显示在页脚中部)
        table.getTableFormat().setHorizontalAlignment(RowAlignment.Center);

        //自动调整表格宽度以适应内容
        table.autoFit(AutoFitBehaviorType.Auto_Fit_To_Contents);

        //保存文档
        doc.saveToFile("设置页脚.docx", FileFormat.Docx_2013);
        doc.close();
    }
}

img

楼主看看这个链接呢:https://www.geeksforgeeks.org/java-program-to-align-the-text-in-a-word-document/
这种需求都是定制性开发,我觉得确实15程序员兼职也不会考虑的,你可以先去尝试链接代码把运行结果告诉我们,我们在帮助你排错代替直接给你代码结果,这是gpt的任务,而不是程序员愿意做的事

设置居中显示

paragraph.setAlignment(ParagraphAlignment.CENTER); 图片和文件居中设置有没有试过。

可以用poi库操作

不知道你这个问题是否已经解决, 如果还没有解决的话:
  • 这篇博客: Java大二校内考试复习题错题整理中的 原始文件为Word文档,故此处格式混乱,仅作简单整理 部分也许能够解决你的问题, 你可以仔细阅读以下内容或跳转源博客中阅读:
    • 深入探究错题,每个重点新开一篇文章,并在此文章中添加新文章链接(待完成)

    • 编译Java程序的命令是:
      A、appletviewer √B、javac
      ×C、java D、javadoc

    • 为了使一个名为MyClass的public类成功编译,需满足以下哪些条件?
      请选择一个正确答案:
      (1)MyClass类中必须定义一个正确的main()方法。
      √(2) MyClass类必须定义在MyClass.java源文件中。
      //(public类的文件名必须和类名一致)
      (3) MyClass类必须定义在MyClass包中。
      ×(4) MyClass类必须被导入。

    • 给出以下代码,请问采取命令行方式java Example I like tests运行该程序,结果是什么?
      请选择一个正确答案:

    class Example {
        public static void main(String[] args) {
            System.out.println(args[l]);
        }
    }
    

    (1)打印输出MyProg
    ×(2) 打印输出I
    √(3) 打印输出Iike // args[1]表示第2个参数,参数用空格分开
    (4) 打印输出3
    (5) 打印输出4
    (6) 打印输出null

    • 给出以下代码,请问采用命令行方式java Example Metallica Justice For All运行该程序,结果是什么?
    class Example {
        public static void main(String[] args) {
            System.out.println(args[4]);
        }
    }
    
    • 请选择一个正确答案:
      ×(1) 打印输出All
      (2) 打印输出For
      (3) 打印输出Justice
      (4)没有输出
      √(5)运行期(Runtime)错误 // 数组越界
      (6)打印输出Metallica

    • Java语言中,负责并发管理的机制是
      A.垃圾回收
      ×B.虚拟机
      C.代码安全
      √D.多线程

    • 分析如下的Java代码段,()编译没有异常和错误
      a) byte b=257;
      b) boolean b=null;
      ×c) float f=1.3; // float 类型初始化数据要加f, 不加f默认为double型
      √d) int i=12;

    • 以下哪个不是Java的基本数据类型
      A、int √B、Boolean C、float D、char

    • 下列关于基本数据类型的取值范围的描述中,正确的一个是
      ×(A)byte类型的取值范围是-128~128 // -128~127
      √(B)boolean类型的取值范围是真或假
      (C )char类型的取值范围是0~65536
      (D)short类型的取值范围是-32767~32767

    • 设有类型定义short i=32; long j=64; 下面赋值语句中不正确的一个是
      (A)j=i; √(B)i=j; ©i=(short)j; (D)j=(long)i;
      // 低级赋给高级自动完成转换

    • 下列说法中,正确的一项是
      (A)字符串"\abcd"的长度为6
      ×(B)False是Java的保留字 // false
      ×(C )123.45L代表单精度浮点型 // 123.45f
      √(D)False是合法的Java标识符

    • 下列哪些语句关于Java内存回收的说明是正确的?
      A、程序员必须创建一个线程来释放内存
      √B、内存回收程序负责释放无用内存
      C、内存回收程序允许程序员直接释放内存
      D、内存回收程序可以在指定的时间释放内存对象

    • 请问,如何强制垃圾回收一个指定的对象?
      请选择一个正确答案:
      (1)调用finalized()方法。
      (2)废弃所有对象的引用。
      (3)使用所有的内存
      √(4)无法强制垃圾回收一个指定的对象。

    • 给出以下代码,请问该程序的运行结果是什么?

    public class Example {
        int cube(int theNum) {
            return theNum * theNum * theNum;
        }
        public static void main(String args[]) {
            int a = 5;
            System.out.println(cube(a));
        }
    }
    

    请选择一个正确答案:
    A. 代码编译失败,因为方法cube()不是公有方法
    B. √代码编译失败,因为方法cube()不是静态方法。 // 程序通过创建对象来运行
    C. 代码编译成功,但运行期抛出异常。
    D. ×打印输出125。

    • 下列标识符(名字)命名原则中,正确的是( )。
      A.类名的首字母小写 ×B.接口名的首字母小写(大驼峰命名法,首字母大写)
      √C.常量全部大写 D.变量名和方法名的首字母大写

    • 下列关于Java语言中要使用的一个变量,不正确的是:
      A、在Java程序中要使用一个变量,必须先对其进行声明;
      ×B、变量声明语句可以在程序的任何地方,只要在变量使用前就可以;
      C、变量不可以在其作用域之外使用;
      √D、局部变量在使用之前可以不初始化,系统使用默认的初始值;
      // 局部变量必须初始化,成员变量可不初始化

    • 下列关于变量作用域的说法中,正确的一项是:
      ×A、方法参数的作用域是方法外部代码段; // 方法内部代码段
      √B、全局变量的作用域是整个类;
      C、局部变量的作用域是整个类; // 方法内
      D、类变量的作用域是类的某个方法; // 是该类

    • 给定如下Java程序,编译运行时,将在()语句出现错误

    public class Test {
        public static void main(String args[]) {
            int i = 0; // a语句
            for (; i < 10; i++) // b语句
            {
                if (i > 5) {
                    String test = "hello"; // c语句
                }
            }
            System.out.println(test); // d语句(局部变量在代码块外失去作用)
        }
    }
    

    a) a b) b c) c √d) d

    • 为某类的一个无形式参数无返回值的方法method书写方法头,使得使用类名作为前缀就可以调用它,该方法头的形式为( )。
      √A. static void method( ) // 类方法 B. public void method( )
      C. final void method( ) // 不可继承 D. abstract void method( )

    • 有关实例方法和类方法的描述正确的是()
      √(A).实例方法能对类变量和实例变量操作
      (B).实例方法只能对类变量操作
      ( C ).实例方法只能对实例变量操作
      ×(D).类方法能对类变量和实例变量操作 // 不能操作实例变量

    • 给定一个Java程序的方法结构如下;以下方法体实现语句正确的是( )。(选择两项)

    public Integer change( int i) {
    		                    
    }
    

    A、Integer int =new Integer( i) ;
    return int;
    B、Integer t = Integer.valueOf( i) ;
    √C、return new Integer( i) ; // 需返回方法前指定的类型
    D、return i;

    • 在Java中下面关于构造方法说法错误的是()
      √A) 对于每一个类,Java虚拟机都提供一个默认构造方法
      // 若已创建构造方法,则不提供默认构造方法
      ×B) 构造方法不能有返回类型
      C) 构造方法可以接收参数
      D) 当父类只有一个带参数的构造方法时,子类必须提供自定义的构造方法

    • 下列关于构造方法的叙述中,错误的是( )
      A.Java语言规定构造方法名与类名必须相同
      B.Java语言规定构造方法没有返回值,但不用void声明
      √C.Java语言规定构造方法不可以重载 // 应使用super
      ×D.Java语言规定构造方法可以声明为private // 无意义

    • 下面关于方法的说法,不正确的是( )。
      (A)Java中的构造方法名必须和类名相同
      ×(B)方法体是对方法的实现,包括变量声明和合法语句
      √©如果一个类定义了构造方法,也可以用该类的默认构造方法
      // 需重新定义默认构造方法
      (D)构造方法可以声明为private

    • 请问,以下哪些修饰符可以使其修饰的变量只能对同包类或子类有效?
      请选择一个正确答案:
      A) public
      B) private
      C) √protected
      D) ×无访问修饰符 // 对子类无效

    在这里插入图片描述

    • !向上转型对象的特点是()
      ×(A).不能操作子类新增的成员对象
      (B).可以操作子类继承或重写的对象
      ( C).可以将对象的上转型对象强制转换到一个子类的对象
      √(D).以上都是
      // 多态: A extends B,B c = new A(),子类对象A上转型为B,引用变量c在编译阶段只能调用其编译时类型B所具有的方法,但运行时则执行它运行时类型A所具有的方法。

    • A派生出子类B,B派生出子类C,并且在Java源代码中有如下声明:

    1. A a0=new A();
    2. A a1 =new B();
    3. A a2=new C();
      问以下哪个说法是正确的? ( )
      A、只有第1行能通过编译
      ×B、第1、2行能通过编译,但第3行编译出错 // Java可以间接继承
      C、第1、2、3行能通过编译,但第2、3行运行时出错
      √D、第1行、第2行和第3行的声明都是正确的
    • 在Java中,对抽象方法描述正确的是:()
      ×A、可以有方法体 // 不可有方法体,即大括号,须在小括号后直接跟上分号
      B、可以出现在非抽象类中
      √C、是没有方法体的方法
      D、抽象类中的方法都是抽象方法

    • !在Java中,下面关于抽象类的描述正确的是()。
      a)抽象类可以被实例化
      ×b)抽象类不能被实例化,因为抽象类没有构造方法
      //抽象类可以有构造方法,只是不能直接创建抽象类的实例对象而已。
      √C) 如果一个类中有一个方法被声明为抽象的,那么这个类必须是抽象类
      d) 抽象类中的方法必须都是抽象的

    • 在Java中,下面关于抽象类的描述正确的是()。
      a抽象类既可以做父类,也可以做子类
      b抽象类没有构造方法
      c抽象类一定含有抽象方法
      √d抽象类不一定含有抽象方法 //可以含有非抽象方法
      //含有抽象方法的一定是抽象类

    • 下面说法错误的是( )。
      A.抽象类既可以做父类,也可以做子类
      √B.abstract和final能同时修饰一个类 //final类不可继承,无意义
      ×C.抽象类中可以没有抽象方法,有抽象方法的类一定是抽象类或接口 //正确
      D.声明为final类型的方法不能在其子类中重新定义

    • 请问,以下哪些是抽象方法的正确形式?
      请选择一个正确答案:
      A. √abstract void Example()
      B. ×abstract void Example(){} //抽象方法不能有方法体,不能有大括号
      C. static abstract void Example()
      D. final abstract void Example()
      E. 方法不能定义为抽象的,只有变量可以是抽象的。

    • 给定Java 代码如下,编译运行后,输出结果是)(选择一项)。

     public class test {
        static int i;
        public int aMethod() {
            i++;
            return i;
        }
        public static void main(String args[]) {
            Test test = new Test();
            test.aMethod();   //静态变量,执行了一次
            System.out.println(test.aMethod());
        }
    }
    

    0 ×b) 1 √c) 2 d) 3

    • 下面程序中类ClassDemo中定义了一个静态变量sum,分析程序段的输出结果。( )
    class ClassDemo {
        public static int sum = 1;
    	public ClassDemo() {
          sum = sum + 5}
    }
    public class ClassDemoTest {
        public static void main(String args[]) {
            ClassDemo demo1 = new ClassDemo();
            ClassDemo demo2 = new ClassDemo();
            System.out.println(demo1.sum);
        }
    }
    

    A. 0 ×B. 6 √C. 11 D. 2

    • !在Java接口中,下列选项里有效的方法声明是( )。
      a) public abstract aMethod( ) ; //没有返回类型,构造方法不能为抽象方法
      √b) public abstract void aMethod( ) ;
      ×c) public static void aMethod( ) ; //没有方法体
      d) protected abstract void aMethod( ) ; //一般为public
      !子类不能窄化接口

    • 定义外部类时不能用到的关键字是( )。
      (A)final (B)public éprivate (D)abstract
      private:只能在同类中使用,而外部类的上一次不是类

    • 以下关于内部类说法错误的是:()
      √!A、内部类不可以声明为abstract //可以为abstract
      B、内部类既具有类的特性,又具有成员的特性
      C、内部类不能与外部类同名
      D、内部类可以访问外部类的private成员变量

    • 以下关于内部类说法错误的是:()
      ×A、内部类可以声明为abstract
      √B、内部类只能和外部类继承同一类型,不能单独继承其他类 //可继承
      C、内部类不能与外部类同名
      D、内部类可以访问外部类的private成员变量

    • 有语句String s=“hello world”; ,以下操作哪个是不合法的?( )
      √A、int i=s.length; //length.() ×B、s+=3;
      //安全自加,自加3的类型和自己类型相同,为string,输出hello world3
      C、String ts=s.trim(); D、String t=s+”!”;

    • 下列代码的执行结果是什么? ()

    String s1 = "aaa"; 
    s1.concat("bbb"); 
    System.out.println(s1); 
    

    √A. The string “aaa”;
    ×B. The string “aaabbb”; //须用s1=s1.concat(“bbb”);
    C. The string “bbbaaa”;
    D. The string “bbb”;

    • Java语言中,String str=“123456789”,System.out.println(str.indexOf(“5”)),输出结果为()。(选择一项)
      a) 6
      ×b) 5
      √c) 4 //indexOf返回第一次出现该字符的索引
      d) -1

    • 在Java中,如果要在字符串类型对象 s= "java"中,得到字母’v’出现的位置,可使用以下()语句
      ×a) s.matches(‘v’) //判断是否与正则表达式相同
      ×b) s.charAt(‘v’) //返回指定索引的char值
      √c) s.indexOf(‘v’)
      d) s.substring(‘v’)

    • 给定如下Java代码,编译运行时,以下()语句的值是true。

    String s=“hello”;
    String t=“hello”;
    String e=new String(“hello”) ;
    char c[]={‘h’,e’,’l’,’l’,o’};
    

    √a) s == t ;
    ×b) t.equals ( c) ; //false,同类型间比较,相同返回true
    c) t == e;
    d) t == c;

    • 关于以下程序段,正确的说法是( )
    1.  String  s1=“abc”+”def”;
    2.  String  s2=new  String(s1)3if(s1= =s2)
    4.     System.out.println(= = succeeded”);   
    5if (s1.equals(s2))
    6.     System.out.println(.equals()  succeeded”);
    

    A、行4与行6都将执行 B、行4执行,行6不执行
    √C、行6执行,行4不执行//比较的是引用 C、行4、行6都不执行

    • 出以下的代码,请问该程序的运算结果是 什么?
     class Example {
         public static void main (String args[]){
    		if("String".replace('T','t')=="String")
    		//replace(A,B):将字符串中第一个A转为B
    			System.out.println("Equal");
    		else
    			System.out.println("Not Equal");
      }
    }
    

    请选择一个正确的答案:
    √(1) 打印输出Equal;
    (2) 打印输出Not Equal;
    (3)代码编译失败。
    (4)打印输出String

    • 给出以下的代码,请问该程序的运算结果是 什么?
    class Example {
        public static void main(String args[]) {
            if ("    String  ".trim() == "String")
                System.out.println("Equal");
            // 仅比较堆内存,调用方法后存储在新的堆内存中
            else
                System.out.println("Not Equal");
        }
    }
    

    请选择一个正确的答案:
    ×(1) 打印输出Equal;
    √(2) 打印输出Not Equal;

    Java 字符串在栈内存和堆内存中的比较、存储方式简介
    (3)代码编译失败。
    (4)运行失败
    • 给出以下的代码,请问该程序的运算结果是 什么?
    class Example {
        public static void main(String args[]) {
            if ("STRING".toUpperCase() == "STRING")
                System.out.println("Equal");
            else
                System.out.println("Not Equal");
        }
    }
    
    String s1 = “abc”;
    String s2 = s1;
    String s3 = new String(“abc”);
    

    A、s1.intern()== s2
    B、s1.intern() == s2.intern()
    C、√s1.intern() == s3
    D、s2.intern() == s3.intern()
    !调用intern方法时,如果常量池已包含等于String方法确定的String对象的字符串,则返回常量池中的该字符串引用。 否则,将此String对象添加到池中,并返回对此String对象的引用。
    详情见:Java intern() 方法 | 菜鸟教程

    • 在异常处理中,如释放资源、关闭文件、关闭数据库等由( )来完成。
      ×A.try子句      B.catch子句
      !√C.finally子句    D.throw子句

    • 下列描述了Java语言通过面向对象的方法进行异常处理的好处,请选出不在这些好处范围之内的一项()
      A. 把各种不同的异常事件进行分类,体现了良好的继承性
      B.把错误处理代码从常规代码中分离出来
      √C.可以利用异常处理机制代替传统的控制流程 //不要替代传统流程
      ×D.可以处理意想不到的异常

    • 下列代码中给出正确的在方法体内抛出异常的是( )。
      A.new throw Exception(" “);√B.throw new Exception(” ");
      C.throws IOException(); ×D.throws IOException;
      throws用于声明将会抛出异常

    • 对于catch子句的排列,下列哪种是正确的( )
      A.父类在先,子类在后
      √B.子类在先,父类在后
      ×C.有继承关系的异常不能在同一个try程序段内 //可以,须遵从B选项
      D.如何排列都可以

    • 运行以下程序段将输出什么? ()

    class E {
        public static void main(String args[]) {
            try {
                throw new ArrayIndexOutOfBoundsException();
                System.out.println("condition 1");// (该句无法被执行)
            } catch (ArrayIndexOutOfBoundsException e) {
                System.out.println("condition 2");
            } finally {
                System.out.println("finally");
            }
        }
    }
    

    √A.编译错误
    ×B.condition 1
    condition 2
    finally
    C.condition 2
    D.condition 2
    finally

    • !给出以下代码,请问该程序的运算结果是什么?
    class Example {
        public static void main(String args[]) {
            System.out.println(3 / 0);
        }
    }
    

    请选择一个正确答案:

    1. 编译失败。
    2. √运行期异常 //Checked异常,无法通过编译;Runtime异常,无法正常运行
    3. ×Java.lang,ArithmeticException 异常抛出。
    4. 打印输出Infinity
    • 能读入字节数据进行Java基本数据类型判断过滤的类是( )。
      ×A.BufferedInputStream B.FileInputStream
      √C.DataInputStream D.FileReader

    • 在通常情况下,下列哪个类的对象可以作为BufferedReader类构造方法的参数( )?
      A.PrintStream(字节输出流) B.FileInputStream (字节输入流)
      C.InputStreamReader(字符输入流、转换流) D.FileWriter (字符输出流)在这里插入图片描述

    • Java系统标准输入对象System.in使用的输入流是( )。
      A.PrintStream √B.InputStream
      C.InputStreamReader ×D.DataIutputStream

    • 在读字符文件Employee.dat时,使用该文件作为参数的类是()
      A.BufferReader
      ×B.DataInputStream
      C.DataOutputStream
      √D.FileInputStream

    • 下列关于流类和File类的说法中错误的一项是( )。
      A.File类可以重命名文件 √B.File类可以修改文件内容
      C.流类可以修改文件内容 ×D.流类不可以新建目录
      !File能新建、删除、重命名文件和目录,但不能访问文件本身。如要访问需使用输入输出流。

    • !下列哪个方法可以将JMenuBar加入JFrame中( )?
      A.setJMenu() B.addJMenuBar()
      ×C.add() √D.setJMenuBar()

    • Container是下列哪一个类的子类( )?
      A.Graphics B.Window C.Applet √D.Component

    • 如下哪个方法可以从 WindowEvent 获取事件源 ?
      A 、 getFrame()
      B 、 getID()
      √C 、 getSource()
      D 、 getEvent()

    • 当单击鼠标或拖动鼠标时,触发的事件是( )。
      A.KeyEvent ×B.ActionEvent C.ItemEvent √D.MouseEvent

    • 对于Java中的布局管理器,以下说法中错误的是()。(选择一项)
      a) FlowLayout 以由上到下的方式从左到右排列组件
      b) BorderLayout 使用”东”、”西”、”南”、”北”,”居中”来指定组件的位置
      √c) GridLayout 可以创建网格布局,网格布局中各组件的大小可以任意调整
      // 大小由组件所处区域来决定(每个组件自动占满整个区域)
      d )可以通过容器的setLayout 方法为容器指定布局管理器

    • 在Java中,与数据库连接的技术是 ()
      A.ODBC
      √B.JDBC //Java Database Connectivity
      C.数据库厂家驱动程序
      D.数据库厂家的连接协议

    • 下面的哪一个关键字通常用来对对象加锁,从而使得对对象的访问是排他的( )?
      A.serialize B.transient
      !√C.synchronized D.static

    • Thread类定义在下列哪个包中( )?
      A.java.io !√B.java.lang
      C.java.util D.java.awt

    • 下列关于Thread类的线程控制方法的说法中错误的一项是( )。
      A.线程可以通过调用sleep()方法使比当前线程优先级低的线程运行
      B.线程可以通过调用yield()方法使和当前线程优先级一样的线程运行
      √C.线程的yield()方法调用结束后,该线程进入运行状态(进入就绪状态)
      ×D.若没有相同优先级的线程处于可运行状态,线程调用yield()方法时,当前线程将继续执行 //正确


如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^

各种库里面都有对应的方法吧

一、插件概述

Windows资源管理器是Windows操作系统中常用的文件管理工具,它能够让用户方便地管理本地硬盘、光驱、网络驱动器等文件资源。本文将介绍如何为Windows资源管理器编写一个插件,实现过滤捕获双击文件和文件夹、关闭文件夹的操作。

二、插件开发

1.开发环境

本插件使用C/C++语言进行开发,开发环境为Visual Studio 2019。

2.创建插件工程

首先打开Visual Studio,选择“新建项目”,在弹出的对话框中选择“Win32控制台应用程序”,填写项目名称和路径后点击“创建”按钮。在弹出的向导中,勾选“DLL”(动态链接库)选项,保持默认设置并点击“完成”按钮创建工程。

3.添加头文件和库文件

为了使用Windows API函数,我们需要添加头文件和库文件。我们需要使用以下头文件:

#include <Windows.h> // Windows API 基础头文件
#include <ShlObj.h> // Shell API 头文件

需要用到的库文件有:

Shell32.lib // Shell API 库文件

可以在项目属性中添加上述库文件路径,或直接使用#pragma comment方式在代码中引用。

4.实现DLL导出函数

编写插件需要导出的函数,供Windows资源管理器调用。

我们需要导出以下两个函数:

BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD fdwReason, LPVOID lpReserved);
BOOL WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv);

其中,DllMain函数是DLL的入口函数,我们可以在其中做一些初始化操作。DllGetClassObject函数用于获取对象指针,这里我们不需要实现该函数。

5.实现捕获双击文件和文件夹的操作

要实现捕获双击文件和文件夹的操作,我们需要实现ShellExecute函数的钩子函数。ShellExecute是Windows API中的一个函数,可以启动一个应用程序或者打开一个文件。

我们需要使用以下函数进行钩子:

HHOOK SetWindowsHookEx(int idHook, HOOKPROC lpfn, HINSTANCE hMod, DWORD dwThreadId);
LRESULT CallNextHookEx(HHOOK hhk, int nCode, WPARAM wParam, LPARAM lParam);
BOOL UnhookWindowsHookEx(HHOOK hhk);

我们将钩子设置为WH_CALLWNDPROCRET,意思是我们会在ShellExecute函数被调用之后,返回结果之前进行一些操作。

代码如下:

LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    CWPSTRUCT* pMsg = (CWPSTRUCT*)lParam;

    if (pMsg->message == WM_DESTROY)
    {
        HWND hFolderWnd = (HWND)pMsg->wParam;
        PostMessage(hFolderWnd, WM_CLOSE, 0, 0);
    }

    if (pMsg->message == WM_COMMAND)
    {
        UINT nID = LOWORD(pMsg->wParam);
        if (nID == 0xE122)
        {
            LPCTSTR lpszFilePath = (LPCTSTR)pMsg->lParam;
            if (lpszFilePath == NULL || lstrlen(lpszFilePath) == 0)
            {
                return CallNextHookEx(hHook, nCode, wParam, lParam);
            }

            // 判断是否是文件夹
            DWORD dwAttr = GetFileAttributes(lpszFilePath);
            if (dwAttr == INVALID_FILE_ATTRIBUTES)
            {
                return CallNextHookEx(hHook, nCode, wParam, lParam);
            }

            if (dwAttr & FILE_ATTRIBUTE_DIRECTORY)
            {
                // 如果是文件夹,取消操作
                return TRUE;
            }
        }
    }

    return CallNextHookEx(hHook, nCode, wParam, lParam);
}

在这里,我们判断pMsg->message的值,如果是WM_COMMAND,并且nID等于0xE122,那么表示这是ShellExecute函数被调用。此时,我们获取到了待打开的文件路径,判断该路径是否是文件夹,如果是,则取消操作,如果不是,则继续执行。

6.实现关闭文件夹的操作

要实现关闭文件夹的操作,我们需要在前面的代码中添加一些内容。

当我们双击一个文件夹时,Windows资源管理器会打开该文件夹并显示其中的内容。如果我们希望关闭该文件夹,我们可以向该文件夹所对应的窗口发送一个WM_CLOSE消息,这样就可以使该文件夹窗口关闭。

代码如下:

if (pMsg->message == WM_DESTROY)
{
    HWND hFolderWnd = (HWND)pMsg->wParam;
    PostMessage(hFolderWnd, WM_CLOSE, 0, 0);
}

在这里,我们判断pMsg->message的值,如果是WM_DESTROY,那么表示该窗口即将被销毁,此时我们获取到窗口句柄,并向该窗口发送一个WM_CLOSE消息,从而实现关闭文件夹的操作。

7.编译和部署

完成代码编写后,我们需要进行编译。编译完成后,我们将得到一个DLL文件。此时,我们需要将该DLL文件放到Windows资源管理器的插件目录下,例如C:\Windows\System32\或C:\Windows\SysWOW64(如果是64位系统)目录中。

最后,我们需要重启Windows资源管理器才能使插件生效。

三、插件使用

完成插件的开发和部署后,我们就可以使用该插件了。

现在,当我们在Windows资源管理器中双击一个文件或者文件夹时,如果该文件或者文件夹是一个文件夹,那么就会被关闭;如果不是一个文件夹,那么就会继续执行默认操作(例如打开文件)。

总结

本文简单介绍了如何为Windows资源管理器编写一个插件,实现过滤捕获双击文件和文件夹、关闭文件夹的操作。我们可以通过钩子函数来截获ShellExecute函数的调用,从而实现取消操作或者关闭文件夹。通过本文的示例,希望读者可以了解到如何使用Windows API函数来实现Windows资源管理器的插件开发。

用java 操作word 使其变成图片和文字对齐 的实现

package com.util;
 
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.imageio.ImageIO;
import javax.imageio.stream.ImageInputStream;
import com.aspose.words.Document;
import com.aspose.words.ImageSaveOptions;
import com.aspose.words.SaveFormat;
 
 
public class OfficeUtils {
 
    /**
     * 验证aspose.word组件是否授权:无授权的文件有水印标记
     * 需要使用(aspose-words-15.8.0-jdk16.jar),版本要对应。无水印
     * @return
     */
    public static boolean isWordLicense()
    {
        boolean result = false;
        try {
            String s = "<License><Data><Products><Product>Aspose.Total for Java</Product><Product>Aspose.Words for Java</Product></Products><EditionType>Enterprise</EditionType><SubscriptionExpiry>20991231</SubscriptionExpiry><LicenseExpiry>20991231</LicenseExpiry><SerialNumber>8bfe198c-7f0c-4ef8-8ff0-acc3237bf0d7</SerialNumber></Data><Signature>sNLLKGMUdF0r8O1kKilWAGdgfs2BvJb/2Xp8p5iuDVfZXmhppo+d0Ran1P9TKdjV4ABwAgKXxJ3jcQTqE/2IRfqwnPf8itN8aFZlV3TJPYeD3yWE7IT55Gz6EijUpC7aKeoohTb4w2fpox58wWoF3SNp6sK6jDfiAUGEHYJ9pjU=</Signature></License>";
            ByteArrayInputStream inputStream = new ByteArrayInputStream(s.getBytes());
            com.aspose.words.License license = new com.aspose.words.License();
            license.setLicense(inputStream);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
 
    //outputStream转inputStream
    public static ByteArrayInputStream parse(OutputStream out) throws Exception
    {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        baos = (ByteArrayOutputStream) out;
        ByteArrayInputStream swapStream = new ByteArrayInputStream(baos.toByteArray());
        return swapStream;
    }
 
    /**
     * word和txt文件转换图片
     * @param inputStream
     * @param
     * @return
     * @throws Exception
     */
    private static List<BufferedImage> wordToImg(InputStream inputStream) throws Exception
    {
        if (!isWordLicense())
        {
            return null;
        }
        try {
            Date start = new Date();
            Document doc = new Document(inputStream);
            ImageSaveOptions options = new ImageSaveOptions(SaveFormat.PNG);
            options.setPrettyFormat(true);
            options.setUseAntiAliasing(true);
            options.setUseHighQualityRendering(true);
            int pageCount = doc.getPageCount();
            //生成前pageCount张,这可以限制输出长图时的页数(方法入参可以传值pageNum)
           /*if (pageCount > pageNum) {
               pageCount = pageNum;
           }*/
            List<BufferedImage> imageList = new ArrayList<BufferedImage>();
            for (int i = 0; i < pageCount; i++)
            {
                OutputStream output = new ByteArrayOutputStream();
                options.setPageIndex(i);
                doc.save(output, options);
                ImageInputStream imageInputStream = javax.imageio.ImageIO.createImageInputStream(parse(output));
                imageList.add(javax.imageio.ImageIO.read(imageInputStream));
            }
            List<BufferedImage> imageList2 = new ArrayList<BufferedImage>();
            //这个重新生成新的图片是因为直接输出的图片底色为红色
            for(int j=0; j<imageList.size(); j++)
            {
                // 生成新图片
                BufferedImage destImage = imageList.get(j);
                int w1 = destImage.getWidth();
                int h1 = destImage.getHeight();
                destImage = new BufferedImage(w1, h1, BufferedImage.TYPE_INT_RGB);
                Graphics2D g2 = (Graphics2D) destImage.getGraphics();
                g2.setBackground(Color.LIGHT_GRAY);
                g2.clearRect(0, 0, w1, h1);
                g2.setPaint(Color.RED);
                // 从图片中读取RGB
                int[] ImageArrayOne = new int[w1 * h1];
                ImageArrayOne = imageList.get(j).getRGB(0, 0, w1, h1, ImageArrayOne, 0, w1); // 逐行扫描图像中各个像素的RGB到数组中
                destImage.setRGB(0, 0, w1, h1, ImageArrayOne, 0, w1); // 设置上半部分或左半部分的RGB
                imageList2.add(destImage);
            }
            Date end = new Date();
            long l=end.getTime()-start.getTime();
            long hour= l / (1000 * 60 * 60);
            long min=  (l-hour*(1000 * 60 * 60 ))/(1000* 60);
            long s= (l-hour*(1000 * 60 * 60 )-min*1000*60)/(1000);
            long ss= (l-hour*(1000 * 60 * 60 )-min*1000*60 -s*1000)/(1000/60);
            System.out.println("word转图片时间:"+min+"分"+s+"秒" + ss + "毫秒");//hour+"小时"+
            return imageList2;
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        }
    }
 
    /**
     * 合并任数量的图片成一张图片
     * @param isHorizontal true代表水平合并,fasle代表垂直合并
     * @param imgs 待合并的图片数组
     * @return
     * @throws IOException
     */
    public static BufferedImage mergeImage(boolean isHorizontal, List<BufferedImage> imgs) throws IOException
    {
        // 生成新图片
        BufferedImage destImage = null;
        // 计算新图片的长和高
        int allw = 0, allh = 0, allwMax = 0, allhMax = 0;
        // 获取总长、总宽、最长、最宽
        for (int i = 0; i < imgs.size(); i++)
        {
            BufferedImage img = imgs.get(i);
            allw += img.getWidth();
            if (imgs.size() != i + 1)
            {
                allh += img.getHeight() + 5;
            } else {
                allh += img.getHeight();
            }
            if (img.getWidth() > allwMax)
            {
                allwMax = img.getWidth();
            }
            if (img.getHeight() > allhMax)
            {
                allhMax = img.getHeight();
            }
        }
        // 创建新图片
        if (isHorizontal)
        {
            destImage = new BufferedImage(allw, allhMax, BufferedImage.TYPE_INT_RGB);
        } else {
            destImage = new BufferedImage(allwMax, allh, BufferedImage.TYPE_INT_RGB);
        }
        Graphics2D g2 = (Graphics2D) destImage.getGraphics();
        g2.setBackground(Color.LIGHT_GRAY);
        g2.clearRect(0, 0, allw, allh);
        g2.setPaint(Color.RED);
 
        // 合并所有子图片到新图片
        int wx = 0, wy = 0;
        for (int i = 0; i < imgs.size(); i++)
        {
            BufferedImage img = imgs.get(i);
            int w1 = img.getWidth();
            int h1 = img.getHeight();
            // 从图片中读取RGB
            int[] ImageArrayOne = new int[w1 * h1];
            ImageArrayOne = img.getRGB(0, 0, w1, h1, ImageArrayOne, 0, w1); // 逐行扫描图像中各个像素的RGB到数组中
            if (isHorizontal) { // 水平方向合并
                destImage.setRGB(wx, 0, w1, h1, ImageArrayOne, 0, w1); // 设置上半部分或左半部分的RGB
            } else { // 垂直方向合并
                destImage.setRGB(0, wy, w1, h1, ImageArrayOne, 0, w1); // 设置上半部分或左半部分的RGB
            }
            wx += w1;
            wy += h1 + 5;
        }
        return destImage;
    }
 
 
    // 测试工具类
    public static void main(String[] args)
    {
        //word转图片格式
        try {
            File file = new File("G:\\test\\test22.docx");
            InputStream inStream = new FileInputStream(file);
            List<BufferedImage> wordToImg = wordToImg(inStream);
            //for(int i=0; i<wordToImg.size(); i++){ //可以保存图片(每页保存为一张)
            //    ImageIO.write(wordToImg.get(i), "jpg", new File("G:\\test\\"+ i +".png")); //将其保存在C:/imageSort/targetPIC/下
            //}
            BufferedImage mergeImage = mergeImage(false, wordToImg);
            //保存图片(长图)
            ImageIO.write(mergeImage, "jpg", new File("G:\\test\\test.png"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
 
}

要使用Java操作Word文档,你会需要Apache POI这样的库。以下是一个简单的示例,演示如何在页脚添加图片并使其与文本对齐:

import org.apache.poi.xwpf.usermodel.*;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;

public class WordFooterImageText {

    public static void main(String[] args) throws Exception {

        XWPFDocument doc = new XWPFDocument();
        XWPFParagraph title = doc.createParagraph();
        XWPFRun run = title.createRun();
        run.setText("这是一个示例文档。");

        // 创建页脚
        XWPFFooter footer = doc.createFooter(HeaderFooterType.DEFAULT);
        final XWPFParagraph paragraph = footer.createParagraph();
        final XWPFRun footerRun = paragraph.createRun();

        // 添加文本
        footerRun.addTab();  // 添加一个制表符以空出一些空间
        footerRun.setText("页脚文本");

        // 添加图片
        final String imgFile = "路径/图片.jpg";
        try(InputStream is = new FileInputStream(imgFile)){
            //将图片转换为byte数组
            BufferedImage bImage = ImageIO.read(is);
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ImageIO.write(bImage, "jpg", bos );
            byte [] bytes = bos.toByteArray();
            //添加图片
            footerRun.addPicture(new ByteArrayInputStream(bytes), XWPFDocument.PICTURE_TYPE_JPEG, imgFile, Units.toEMU(200), Units.toEMU(200));
        }

        try(OutputStream os = new FileOutputStream("Test_Document.docx")){
            doc.write(os);
        }

        System.out.println("创建完成");
    }
}

这个示例首先创建了一个新的Word文档并在其主体部分添加了一些文字。然后在页脚添加了一个新的段落,并在该段落添加了一些文字。

接着,它读入了一个JPEG格式的图片,将它转换为byte数组,并添加到页脚段落。最后,它将这个Word文档保存到文件"Test_Document.docx"中。

请注意,这只是一个很基本的示例。你可能需要对这个代码进行修改以达到你的特定需求,比如调整图片的大小或者位置,修改文本的样式等等。